前言
在學習繼承相關的知識點時,遇到了一個問題,
下面這段代碼中的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方法實作了屬性的繼承,
當然,如果是共享的屬性或方法,還是利用原型鏈來繼承比較好~
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/100511.html
標籤:JavaScript
上一篇:JS變數賦值
