前言 在學習繼承相關的知識點時,遇到了一個問題。 下麵這段代碼中的 是什麼意思?為什麼它就表示 繼承到了父類Animal的屬性 呢? 後來回顧了new操作符的知識點,這才豁然開朗。 一、瞭解new操作符 通過構造模式來創建對象的關鍵一步就是 "new操作符" ,它會根據構造函數創建實例對象。 另外, ...
前言
在學習繼承相關的知識點時,遇到了一個問題。
下麵這段代碼中的Animal.call(this, name);
是什麼意思?為什麼它就表示繼承到了父類Animal的屬性呢?
function Animal(name) {
this.name = name;
}
Animal.prototype.say = function() {
return this.name;
}
function Cat(name, color) {
Animal.call(this, name);
this.color = color;
}
Cat.prototype = Object.create(Animal.prototype);
Cat.prototype.constructor = Cat;
var cat = new Cat('小黃', 'yellow');
後來回顧了new操作符的知識點,這才豁然開朗。
一、瞭解new操作符
通過構造模式來創建對象的關鍵一步就是new操作符,它會根據構造函數創建實例對象。
另外,很重要的是,實例化的過程中,this會指向實例對象,這樣就可以將對應的屬性和方法掛載到實例對象上。
我們列印一下this,發現它確實是實例對象,而非預設的window。
function Foo(name) {
console.log(this);
this.name = name;
}
var foo = new Foo('mm');
二、瞭解call方法
call方法是函數特有的,它用來改變this的指向。
這背後的意思就是:把一個函數的方法綁定到相應的對象上,於是這個對象就就可以調用它。
具體啥意思呢?看下代碼:
function add(x, y) {
console.log('綁定對象是', this);
return x + y;
}
var res1 = add(1, 2);
console.log(res1);
var obj = {};
var res2 = add.call(obj, 3, 4);
console.log(res2);
雖然obj沒有add方法,但是它通過call方法就可以調用了。觀察發現,this從window改變到了obj身上!
三、call方法與繼承
大家想想,利用this被改變的這個特點,我們只要寫成構造函數的樣子,不就能把一系列的屬性和方法悄無聲息地掛載到obj上了嗎?!
什麼意思呢?比如this.name = name; 既然this改變成obj了,那麼原來的代碼就變成這樣了 ===> obj.name = name;
看下代碼:
function foo(name) {
console.log('綁定對象是', this);
this.name = name;
this.say = function() {
console.log(`我叫${this.name},我喜歡編程!`);
}
}
foo(); // 直接調用foo,this指向window
var obj = {};
console.log('調用call方法前的obj:',obj);
foo.call(obj, 'mm');
console.log('調用call方法後的obj:',obj);
在改變了this指向後,屬性和方法掛載到了對象上,這不就相當於一種繼承嗎?
四、繼承
再回過頭來看下起初的代碼:
function Animal(name) {
this.name = name;
}
Animal.prototype.say = function() {
return this.name;
}
function Cat(name, color) {
Animal.call(this, name);
this.color = color;
}
Cat.prototype = Object.create(Animal.prototype);
Cat.prototype.constructor = Cat;
var cat = new Cat('小黃', 'yellow');
第一步,將Cat函數的原型指向Animal的原型對象,這樣Cat就繼承了Animal原型上的say方法;
Cat.prototype = Object.create(Animal.prototype);
在改變了Cat的原型對象後,它的constructor屬性也隨之改變,指向了Animal,因此必須要把它轉回來,所以,
第二步,將Cat的原型對象指向本身(Cat);
Cat.prototype.constructor = Cat;
第三步,實例化Cat對象。
var cat = new Cat('小黃', 'yellow');
- 首先實例化對象,此時的this綁定到了Cat的實例對象;(然後依次執行以後的代碼)
Animal.call(this, name);
此時實例對象調用Animal方法,傳入參數name,這樣實例對象上就有了name;this.color = color;
接下來是Cat自身的屬性color。將color掛載到實例對象上,這樣實例對象上就有了color。- 返回實例對象。
第四步,將實例對象賦值給cat。
最後,cat是否繼承了Animal,又是否有自己的屬性color呢?
console.log(cat);
console.log(cat.say());
OK,我們成功了。
五、總結
綜上,理解Animal.call(this, name);
的關鍵是:this綁定對象綁定的是那個實例對象,call方法實現了屬性的繼承。
當然,如果是共用的屬性或方法,還是利用原型鏈來繼承比較好~