改變函式作用域(call、 apply 、bind)
call、 apply 、bind
同異
1)第一個引數都是this的上下文
2)apply第二個引數是陣列,call和bind後面都是引數列表
3) call和apply預設會自動執行,bind需要在後面加()來自動執行
4)bind是ES5語法,它是新建立一個函式,然後把它的上下文繫結到bind()括號中的引數上,然後將它返回。
this 的指向
this 永遠指向最後呼叫它的那個物件,箭頭函式則不是
var name = "windowsName";
var a = {
name: "Cherry",
fn: function () {
console.log(name); // windowsName
console.log(this.name); // Cherry
}
}
a.fn();
fn 的內部的 this 是物件 a,因此 this.name 會找到 該函式內的變數 name
而name 前面沒有顯示的函式呼叫,其實它是 window.name 因此就會找到函式外的變數 name
var name = "windowsName";
var a = {
name: "Cherry" ,
fn: function () {
console.log(this.name); // Cherry
}
}
var f = a.fn();
f;
雖然將 a 物件的 fn 方法賦值給變數 f 了,但是沒有呼叫,而,“this 永遠指向最後呼叫它的那個物件”, 所以最後是 window.f = window.a.fn()
,多層巢狀,只算最靠近方法的那層。所以 this 指向的是 a。
如何使用
var name = 'hello';
var a = {
name: "Cherry",
fn: function (a, b) {
console.log(this.name+":" +(a + b));
}
}
var b = a.fn;
// 前三個輸出都是 Cherry: 3
b.bind(a, 1, 2)();
b.apply(a,[1,2]);
b.call(a,1,2);
b(); // hell0 NAN
第四個呼叫顯示了使用 call、 aply 、bind 之後,執行時 的this 由 window 變為 a ,即 a.fn(),為而第四個 任然是 window.fn()
箭頭函式的 this 始終指向函式定義時的 this,而非執行時。箭頭函式需要記著這句話:“箭頭函式中沒有 this 繫結,必須通過查詢作用域鏈來決定其值,如果箭頭函式被非箭頭函式包含,則 this 繫結的是最近一層非箭頭函式的 this,否則,this 為 undefined”。
建構函式繫結
使用call或apply方法,將父物件的建構函式繫結在子物件上
function Animal(){
this.species = "動物";
}
function Cat(name,color){
Animal.apply(this, arguments);
this.name = name;
this.color = color;
}
var cat1 = new Cat("大毛","黃色");
alert(cat1.species); // 動物
prototype模式
讓”貓”的prototype物件,指向一個Animal的例項,那麼所有”貓”的例項,就能繼承Animal了。
function Animal(){
this.species = "動物";
}
function Cat(name,color){
this.name = name;
this.color = color;
}
alert(Cat.prototype.constructor.toString());
// function Cat(name,color){
// this.name = name;
// this.color = color;
// }
Cat.prototype = new Animal();
var cat1 = new Cat('小H','小藍色');
alert(cat1.species); // 動物
alert(Cat.prototype.constructor.toString());
// function Animal(){
// this.species = "動物";
// }
Cat.prototype.constructor = Cat; alert(Cat.prototype.constructor.toString());
// function Cat(name,color){
// this.name = name;
// this.color = color;
// }
alert(cat1.species); // 動物
分析
"Cat.prototype = new Animal();
”
任何一個prototype物件都有一個constructor屬性,指向它的建構函式.Cat.prototype.constructor是指向Cat的;加了這一行以後,Cat.prototype.constructor指向Animal。也就是說,這行刪除了prototype 物件原先的值,然後賦予一個新值
這顯然會導致繼承鏈的紊亂(cat1明明是用建構函式Cat生成的),因此我們必須手動糾正,將Cat.prototype物件的constructor值改為Cat。"Cat.prototype.constructor = Cat"