摘要:相當于在用原型繼承編寫復雜代碼前理解原型繼承模型十分重要。同時,還要清楚代碼中原型鏈的長度,并在必要時結束原型鏈,以避免可能存在的性能問題。
至于繼承,js的繼承與java這種傳統的繼承不一樣.js是基于原型鏈的繼承.
在javascript里面,每個對象都有一個prototype屬性,指向它的原型對象.這個原型對象里面同時還有自己的原型,原型一環扣一環,直到某個對象的原型為null,這一級一級的鏈結構就是原型結構.
js的原型鏈繼承
繼承屬性
js屬性查找:由于js原型鏈的存在,當查找一個對象屬性時候,不只是在對象上查找,還會沿著該js對象的原型鏈往上查找,知道找到一個匹配的屬性或者查找到原型鏈末尾.當然如果js對象上與其原型的對象上都有同名的屬性,我們遵循該屬性的作用域就近原則(術語叫做"屬性遮蔽").
var Ele = function(){ this.a = 1; this.b = 2; } var Obj = function(){ this.c = 3; this.b = 4; } Ele.prototype = new Obj(); var ele1 = new Ele(); console.log(ele1.a);//1 console.log(ele1.b);// 2 console.log(ele1.c);// 3 console.log(ele1.d);//undefined
繼承方法
在 JavaScript 里,任何函數都可以添加到對象上作為對象的屬性/方法。函數的繼承與其他的屬性繼承沒有差別,包括上面的“屬性遮蔽”(這種情況相當于其他語言(java)的方法重寫)。
var student= { age : 20, name: "cp", sayhi : function(){ console.log("hi"); } } var s1 = Object.create(student); //一種創建對象的方法,后面會寫博客介紹.s1.prototype是student s1.name = "kobe"; console.log( s1.name ); // "kobe" console.log( s1.age ); // 20 console.log( s1.sayhi() ); // hi
多種方法創建對象及生產原型鏈
普通對象字面量創建對象
var o = { a: 1 }; console.log(o.hasOwnProperty("a")); //true // o這個對象繼承了Object.prototype上面的所有屬性 // 所以可以這樣使用 o.hasOwnProperty("a").判斷一個對象是否還有一個屬性 // hasOwnProperty 是Object.prototype的自身屬性。 // Object.prototype的原型為null。 // 原型鏈如下: // o ---> Object.prototype ---> null var a = ["yo", "whadup", "?"]; // 數組的實例對象都繼承于Array.prototype // (indexOf, forEach等方法都是從它繼承而來). // 原型鏈如下: // a ---> Array.prototype ---> Object.prototype ---> null function f(){ return 2; } // 函數都繼承于Function.prototype // (call, bind等方法都是從它繼承而來): // f ---> Function.prototype ---> Object.prototype ---> null - 使用構造函數(構造器)創建對象 `function Student() { this.job = "讀書"; this.tag = "年輕"; } function BoyStudent() { this.sex = "boy"; } BoyStudent.prototype = new Student(); var xiaoMing = new BoyStudent(); console.log(xiaoMing.sex); //boy console.log(xiaoMing.tag); //年輕 // xiaoMing是生成的對象,他的自身屬性有"sex". // 在BoyStudent被實例化時,BoyStudent.[[Prototype]]指向了Student.prototype.
使用Object.create()創建對象,新對象的原型就是調用 create 方法時傳入的第一個參數:
var a = {a: 1}; // a ---> Object.prototype ---> null var b = Object.create(a); // b ---> a ---> Object.prototype ---> null console.log(b.a); // 1 (繼承而來) var c = Object.create(b); // c ---> b ---> a ---> Object.prototype ---> null var d = Object.create(null); // d ---> null console.log(d.hasOwnProperty); // undefined, 因為d沒有繼承Object.prototype
使用 class 關鍵字
ECMAScript6 引入了一套新的關鍵字用來實現 class。使用基于類語言的開發人員會對這些結構感到熟悉,但它們是不一樣的。 JavaScript 仍然是基于原型的,這點一直不變。這些新的關鍵字包括 class, constructor, static, extends, 和 super.(跟java的關鍵字一樣,構造器,靜態,繼承,超類)
"use strict"; //類 Person class Person(){ constructor(name , age){ this.name = name; this.age = age; }; } // 類Girl繼承Person class Girl extends Person(){ constructor(name , age){ super(name , age); } getinfo(){ return this.name + "," + this.age; } } var girl = new Girl("kobe",20);
原型繼承的性能
在原型鏈上查找屬性比較耗時,對性能有副作用,盡量避免,這在性能要求苛刻的情況下很重要。另外,訪問不存在的屬性時會遍歷整個原型鏈,浪費資源。
遍歷對象的屬性時,原型鏈上的每個可枚舉屬性都會被枚舉出來。
檢測對象的屬性是定義在自身上還是在原型鏈上,有必要使用 hasOwnProperty 方法,所有繼承自 Object.proptotype 的對象都包含這個方法,返回布爾值,是 JavaScript 中唯一一個只涉及對象自身屬性而不會遍歷原型鏈的方法。
注意:僅僅通過判斷值是否為 undefined 還不足以檢測一個屬性是否存在,一個屬性可能存在而其值恰好為 undefined。
關于原生對象的原型擴展
理論上我們不應該去擴展Object.prototype,或者其他內置對象的原型,像Array.prototype等。
我們去擴展內置對象原型的唯一理由是引入新的 JavaScript 引擎的某些新特性,比如 Array.forEach。
理解prototype與Object.getPrototypeOf區別
function A(a){ this.varA = a; } // 以上函數 A 的定義中,既然 A.prototype.varA 總是會被 this.varA 遮蔽, // 那么將 varA 加入到原型(prototype)中的目的是什么? A.prototype = { varA : null, // 既然它沒有任何作用,干嘛不將 varA 從原型(prototype)去掉? // 也許作為一種在隱藏類中優化分配空間的考慮? // https://developers.google.com/speed/articles/optimizing-javascript#Initializing instance variables // 將會驗證如果 varA 在每個實例不被特別初始化會是什么情況。 doSomething : function(){ // ... } }
當你 var a1 = new A();js內部就會設置a1.[[prototype]] == A.prototype .
如果你再 var a2 = new A();那么 a1.doSomething 事實上會指向Object.getPrototypeOf(a1).doSomething,
它就是你在 A.prototype.doSomething 中定義的內容。
比如:Object.getPrototypeOf(a1).doSomething == Object.getPrototypeOf(a2).doSomething == A.prototype.doSomething。
prototype 是用于類型的,而 Object.getPrototypeOf() 是用于實例的(instances),兩者功能一致。
var Fx = function(){}; var fx = new Fx();
相當于
var fx = new Object(); fx[[prototype]] = Fx.prototype; Fx.call(fx);
在用原型繼承編寫復雜代碼前理解原型繼承模型十分重要。同時,還要清楚代碼中原型鏈的長度,并在必要時結束原型鏈,以避免可能存在的性能問題。此外,除非為了兼容新 JavaScript 特性,否則,永遠不要擴展原生的對象原型。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/80968.html
摘要:原型對象是由創建的,因此原型對象的構造函數是構造函數也可以是稱為對象,原型對象也就繼承了其生父構造函數中的數據,也同時繼承了原型對象的數據。當然這條原型鏈中的數據,會被還是還是這類構造函數繼承,但是不會被這些繼承,他們不處于同一個鏈條上。 js中,Function的本質是什么?Object的本質又是什么?js中有幾條原型鏈? showImg(https://segmentfault.c...
摘要:是完全的面向對象語言,它們通過類的形式組織函數和變量,使之不能脫離對象存在。而在基于原型的面向對象方式中,對象則是依靠構造器利用原型構造出來的。 JavaScript 函數式腳本語言特性以及其看似隨意的編寫風格,導致長期以來人們對這一門語言的誤解,即認為 JavaScript 不是一門面向對象的語言,或者只是部分具備一些面向對象的特征。本文將回歸面向對象本意,從對語言感悟的角度闡述為什...
摘要:創建自定義的構造函數之后,其原型對象只會取得屬性,其他方法都是從繼承來的。優缺點寄生式繼承在主要考慮對象而不是創建自定義類型和構造函數時,是十分有用的。 原文鏈接:https://kongchenglc.coding.me... 1.原型鏈 ??js的繼承機制不同于傳統的面向對象語言,采用原型鏈實現繼承,基本思想是利用原型讓一個引用類型繼承另一個引用類型的屬性和方法。理解原型鏈必須先理...
摘要:原型鏈與繼承當談到繼承時,只有一種結構對象。如果對該圖不怎么理解,不要著急,繼續往下看基于原型鏈的繼承對象是動態的屬性包指其自己的屬性。當使用操作符來作用這個函數時,它就可以被稱為構造方法構造函數。 原型鏈與繼承 當談到繼承時,JavaScript 只有一種結構:對象。每個實例對象(object )都有一個私有屬性(稱之為proto)指向它的原型對象(prototype)。該原型對象也...
摘要:對象詳解對象深度剖析,深度理解對象這算是醞釀很久的一篇文章了。用空構造函數設置類名每個對象都共享相同屬性每個對象共享一個方法版本,省內存。 js對象詳解(JavaScript對象深度剖析,深度理解js對象) 這算是醞釀很久的一篇文章了。 JavaScript作為一個基于對象(沒有類的概念)的語言,從入門到精通到放棄一直會被對象這個問題圍繞。 平時發的文章基本都是開發中遇到的問題和對...
閱讀 2407·2021-10-14 09:43
閱讀 2440·2021-09-09 09:34
閱讀 1604·2019-08-30 12:57
閱讀 1207·2019-08-29 14:16
閱讀 723·2019-08-26 12:13
閱讀 3204·2019-08-26 11:45
閱讀 2288·2019-08-23 16:18
閱讀 2660·2019-08-23 15:27