首先回顧一下原型式繼承:javascript
function object(obj){ function F(){} f.prototype = obj; return new F(); }
寄生式繼承是與原型式繼承緊密相關的一種思路,而且一樣也是由克羅克福德推而廣之的。java
說到寄生式繼承不得不說工廠模式和寄生構造函數模式建立對象。下面來回顧一下工廠模式建立對象:函數
function createPerson(name, age, job){ let o = new Object(); o.name = name; o.age = age; o.job = job; o.sayName = function(){ console.log(this.name); } return o; } let p = createPerson('bob', 18, 'JavaScript'); p.sayName();//bob
在函數體內建立了一個對象,而後對這個對象進行加強,添加一些屬性和方法,再返回這個對象,使用時直接調用createPerson
,並將參數傳給它,就獲得了咱們想要的對象,但本質上 createPerson
不過是封裝了用於加強o
的代碼。this
再看寄生構造函數模式建立對象:.net
function Person(name, age, job){ let o = new Object(); o.name = name; o.age = age; o.job = job; o.sayName = function(){ console.log(this.name); } return o; } let p = new Person('bob', 18, 'JavaScript'); p.sayName();//bob
思路其實和工廠模式同樣,只不過建立對象是經過new關鍵字進行的,而工廠模式是直接調用。prototype
寄生式繼承的思路就是相似上面這樣:建立一個用於封裝繼承過程的函數,該函數內部以某種方式來加強對象,而後返回這個對象,該對象就是原對象的一個子對象。來看下面的示例:code
function extend(obj){ let child = object(obj);//或者使用Object.create(obj); child.sayHi = function(){ console.log('hi'); } return child; }
建立extend
函數,接收的參數就是將要繼承的對象。函數體內使用object
函數返回了obj
的子對象child
,而後經過給child
添加sayHi
方法,對child
進行了加強,最後返回child
。與原型式繼承相比,寄生式繼承幫咱們封裝了加強的代碼,而原型式繼承須要咱們手動書寫加強的代碼。來看下面的示例:對象
let p = { name: 'bob', friends: ['jack', 'rose'] } //使用寄生式繼承 let p2 = extend(p); p2.sayHi();//hi //使用原型式繼承 let p3 = object(p); p3.sayHi = function(){ console.log('hi'); } p3.sayHi();//hi
在JavaScript繼承(四)——原型式繼承中提到的Object.create
方法,其能夠接受一個或兩個參數,接收一個參數時等同於object函數,也就是原型式繼承,其實接收兩個參數就等同於寄生式繼承。來看下面的示例:blog
let p4 = Object.create(p, { sayHi: { value: function(){ console.log('hi'); } } }); p4.sayHi();//hi
因此不管是原型式繼承仍是寄生式繼承,使用Object.create
就夠了。繼承
實際上,寄生式繼承基本上能夠替代原型式繼承,寄生式繼承能夠看做原型式繼承的加強。須要注意的是使用寄生式繼承來爲對象添加函數,會因爲不能作到函數複用而下降效率,這一點與構造函數模式相似。關於構造函數模式,以下所示:
function Person(name, age, job){ this.name = name; this.age = age; this.job = job; this.sayName = function(){ alert(this.name); } } let p1 = new Person('zhangsan', 18, 'JavaScript'); let p2 = new Person('lisi', 20, 'Java');
能夠參考這篇文章--JavaScript建立對象(二)——構造函數模式。