開始的代碼是這樣的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 方法,執行之
建立一個實例對象,對象的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。對象
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
先看「原型鏈繼承法」中的操做: 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