原型鏈
不知道什麼是原型鏈?
來讀幾個關鍵詞:函數
哥歐 構 構造函數 構造函數 構造函數 實例 實例 實例 原型對象 原型對象 原型對象 prototype prototype prototype __proto__ __proto__ __proto__ constructor constructor constructor instanceof instanceof instanceof
function newInstanceof (left, right) { let leftProto = left.__proto__; let rightPrototype = right.prototype while(true) { if(leftProto === rightPrototype) { return true; } else if (leftProto === null) { return false; } else { leftProto = leftProto.__proto__ } } }
function FatherA() { this.money = 100000; } function ChildA() { FatherA.call(this); this.soliloquy = '開心'; } var childAng = new ChildA(); FatherA.prototype.makeMoneyWay = function () { console.log('next lottery number is ……'); }
假設某地有個習俗,FatherA會給ChildA準備10萬教育基金,
構造函數繼承能夠完美的讓孩子獲取到準備好的教育基金。
然而這個時候FatherA新領悟到了一串神祕代碼,childAng卻用不了性能
childAng.makeMoneyWay(); // 會報錯
這樣的繼承感受不是親身的。ui
function FatherB() { this.money = 100000; this.card = ['工商', '建設']; } function ChildB() { this.soliloquy = '開心'; } ChildB.prototype = new FatherB() var childBobo = new ChildB(); var childBigShuan = new ChildB(); FatherB.prototype.makeMoneyWay = function () { console.log('next lottery number is ……'); } childBobo.card.push('招商'); // 引用類型受影響 childBobo.money += 1000; // 值類型在此不受影響
原型鏈繼承解決了構造函數的問題,FatherB上新的技能,ChildB的實例也能很好的使用。
圖示:
this
然而一個新問題就是,當實例有多個例如childBobo(波波)和childBigSuan(大栓)。
波波這個時候新辦了一張銀行卡,結果大栓立馬能用,這樣讓波波以爲很沒有隱私,哦不,是很不公平,憑啥你刷個人卡。spa
function FatherC() { this.money = 100000; this.card = ['工商', '建設']; } function ChildC() { FatherC.call(this); this.soliloquy = '開心'; } ChildC.prototype = new FatherC() var childCuifa = new ChildC(); var childChizi = new ChildC(); FatherC.prototype.makeMoneyWay = function () { console.log('next lottery number is ……'); } childCuifa.card.push('招商'); childCuifa.money += 1000;
出了問題總要解決,這時候出現了由構造函數和原型鏈的組合繼承,這樣既讓ChildC實例的數據相互獨立,也讓ChildC能獲取到FatherC的新技能。
社會問題是解決了。新的問題就是性能問題,這類繼承會調用FatherC兩次。顯然用的越多,消耗的資源越多。(雖然如今硬件很發達,可是1我的睡100平米的牀終究仍是不方面,起夜還沒下牀呢就尿了)prototype
function FatherD() { this.money = 100000; this.card = ['工商', '建設']; } function ChildD() { FatherD.call(this); this.soliloquy = '開心'; } ChildD.prototype = FatherD.prototype var childDazhu = new ChildD(); var childDabing = new ChildD(); console.log('分不清是孩子仍是父輩', childDazhu instanceof ChildD, childDazhu instanceof FatherD); console.log('大柱的構造函數指向的是ParentD', childDazhu.constructor);
上一個組合繼承中code
ChildC.prototype = new FatherC()
這行代碼主要是爲了讓ChildC.prototype與new FatherC()的__proto__在一條原型鏈上。
因此換個思路,new FatherC()的__proto__也就是FatherC.protorype。
圖示:
對象
替換後,既不會再執行FatherC,也讓原型鏈合併到了一塊兒。
這個方案的隱藏問題就是,childDazhu(大柱)這個實例,會讓人不知道是孩子仍是爸爸。blog
function FatherE() { this.money = 100000; this.card = ['工商', '建設']; } function ChildE() { FatherE.call(this); this.soliloquy = '開心'; } ChildE.prototype = Object.create(FatherE.prototype); ChildE.prototype.constructor = ChildE; var childErgo = new ChildE(); var childErwa = new ChildE(); var fatherErjun = new FatherE(); console.log('能分清是孩子仍是父輩', childErgo instanceof ChildE, childErgo instanceof FatherE); console.log('二狗的構造函數已指向childE', childErgo.constructor);
圖示:
繼承
關鍵代碼
Object.create
Object.create建立對象的方法就是用原型鏈來鏈接的。
Object.create()方法建立一個新對象,使用現有的對象來提供新建立的對象的__proto__。
參考自:
https://developer.mozilla.org...var a = {name:'a'};var b = Object.create(a);b.__proto__ === a; // true這樣ChildE與FatherE.prototype就在一條鏈上面了,而且數據也進行了隔離,此時修改ChildE原型對象的構造函數指向,不會影響到FatherE的原型對象。也讓childErgo(二狗)有了肯定的歸屬。幸福的結局!!