javascript繼承的我的總結

開始的代碼是這樣的app

var Animal = function(name){
    this.name = name;
};
Animal.prototype.jump = function(){
    console.log('jumped');
};

原型鏈繼承法(對象之間的繼承)

優勢:將可共享的可重用的部分(屬性或者方法)遷移到原型鏈上,將不可重用的部分做爲對象的實例屬性(屬性)函數

var Human = function(name){
    this.name = name;
};
// 這一步會使得
// Human.prototype.constructor = Animal;
// 因此須要從新手動重定向
Human.prototype = new Animal;//將父構造函數的實例對象賦值給一個子構造函數的原型
// 若是不更改
// 經過`Human`構造器構造出來的對象的構造器會變成`Animal`而不是`Human`
Human.prototype.constructor = Human;(有new就要手動修改)
var man = new Human('HaoyCn');
man.jump();

如今,對象 man 可使用 Animal.prototype.jump 方法,查找過程是:this

man 自身沒有jump方法
查找 man.constructor.prototype,即Human.prototype,可Human.prototype自己也沒有 jump 方法,而它又是一個由Animal 構造的對象,因此
查找 Animal.prototype,在其中找到了 jump 方法,執行之

clipboard.png

建立一個實例對象,對象的prototype指向構造函數的原型(man.constructor.prototype),構造函數中的this指向這個實例對象,運行構造函數,對實例對象的屬性進行賦值,返回這個實例對象spa

僅從原型繼承法(構造函數之間的繼承)

優勢:提升了運行時的效率,沒有建立新對象出來。prototype

var Human = function(name){
    this.name = name;
};
Human.prototype = Animal.prototype;//將一個父構造函數的原型直接賦值給子構造函數的原型
var man = new Human('HaoyCn');
man.jump();

man 自身沒有jump方法
查找 man.constructor.prototype,即Human.prototype,Human.prototype是對Animal.prototype 的引用,在其中找到了 jump 方法,執行之減小了一步。
然而代價則是:對 Human.prototype 的修改都會影響到 Animal.prototype,由於前者是對後者的引用。code

一個致命缺點就是,沒法修正子類構造的對象的 constructor。對象

clipboard.png

man.constructor === 
    man.__proto__.constructor === 
    Human.prototype.constructor ===
    Animal.prototype.constructor ===
Animal

臨時構造函數繼承法(類式繼承,構造函數之間的繼承+對象間的繼承)

var F = function(){};//建立要給空的函數(構造函數:中介構造器)
F.prototype = Animal.prototype;//父構造函數的原型賦值給空構造函數的原型

var Human = function(name){
    this.name = name;
};
Human.prototype = new F;//空(父)構造函數的實例對象賦值給子構造函數的原型
Human.prototype.constructor = Human;//手動修改重定向constructor(有new就要修改)
Human.prototype.sing = function(){
    console.log('Mayday');
};
var man = new Human('HaoyCn');
man.jump();
man.sing();

咱們對 Human.prototype 的任何改變都變成了對一個由中介構造器建立的對象的屬性的修改。jump查找過程是:繼承

man 自身沒有jump方法
查找 man.constructor.prototype,即Human.prototype,可Human.prototype自己也沒有jump 方法,而它又是一個由 F 構造的對象,因此
查找 F.prototype,即 Animal.prototype,在其中找到了 jump 方法,執行之ip

clipboard.png

先看「原型鏈繼承法」中的操做:
Human.prototype = new Animal;
// 這將形成:
// Human.prototype.name = undefined;// 沒有給`Animal`傳入參數之故
也就是說,Human.prototype 會多出沒必要要的屬性來,而中介器則避免了這種沒必要要的屬性。

構造器借用法

以上繼承法共通的一個缺點在於,Human 構造器構造的對象雖然能夠共用 Animal.prototype,但對於name 屬性而言,Human 構造器只能本身再寫一遍構造 name 屬性,爲何不把初始化屬性的方法也共(借)用呢?
構造器借用法應運而生。如今咱們把 name 屬性的建立仍是交給 Animal,而後再爲 Human 增長country 屬性。咱們在「臨時構造器法」基礎上進一步完善之。原型鏈

var F = function(){};//建立要給空的函數(構造函數:中介構造器)
F.prototype = Animal.prototype;//父構造函數的原型賦值給空構造函數的原型
//建立子構造函數
var Human = function(){
    Animal.apply(this,arguments);//this.Animal(arguments):借用構造器Animal,是初始化屬性的方法也共用(偷懶)
    this.country = arguments[1];
}

Human.prototype = new F;//空(父)構造函數的實例對象賦值給子構造函數的原型
Human.prototype.constructor = Human;//手動修改重定向constructor

var man = new Human('HaoyCn','China');
console.log(man.country);// China

clipboard.png

相關文章
相關標籤/搜索