從上一篇可以知道,不同的函式呼叫會造成 this
的不同,但我們能不能在呼叫時候明確指定呢?
當然可以。會有這個想法是因為往往在執行某支函式時想要用回呼函式,但發現 this
總是顯示 window
,為了確保 this
是我們想要的物件或函式,就必須使用 apply
及call
。
可能有點難以理解,這邊我們來看一個範例:
var obj = {
price : 20,
sum : function (cb){
cb(100);
}
}
function getData(val){
console.log(this);
}
obj.sum(getData);//Window
可以看到我們預期 getData
的 this
是 obj
物件,但顯示出來的卻是 window
。
這是因為,當沒有特定指明 this
的情況下,預設綁定 (Default Binding) this
為 「全域物件」,也就是 window
。
所以除非我們透過 call
及 apply
強制指定 this
為自己想要的物件或函式,不然 getData
都會是預設的 window
。
就算包裹在物件內也是一樣:
var obj = {
price : 20,
sum : function (cb){
cb(100);
},
getData : function (val){
console.log(this,val);
}
}
obj.sum(obj.getData);//Window
好,現在我們知道call
及 apply
可以強制指定 this
了,那要怎麼用呢?call
及 apply
的作用完全一樣,差別只在傳入參數的方式有所不同。call
後面只接受單個值的引數,而 apply
只接受一個陣列的引數:
var obj = {
price : 20
};
function funA(x,y){
console.log(this);
console.log(x,y);
}
funA.call(obj,2,3);
//{price: 20}
//2 3
funA.apply(obj,[10,100]);
//{price: 20}
// 10 100
所以剛剛的例子我們可以這樣改寫:
var obj = {
price : 20,
sum : function (cb){
cb.call(obj,100);
},
getData : function (val){
console.log(this,val);
}
}
obj.sum(obj.getData);
我們在第七天時有提到函式重載的範例:
function addMethod (obj, key, fn) {
var old = obj[key];
obj[key] = function () {
if (fn.length === arguments.length) {
return fn(arguments);
} else if (typeof old === "function") {
return old(arguments);
}
}
}
其實這樣改寫會比較妥當:
function addMethod (obj, key, fn) {
var old = obj[key];
obj[key] = function () {
if (fn.length === arguments.length) {
return fn.apply(this,arguments);
} else if (typeof old === "function") {
return old.apply(this,arguments);
}
}
}
以上就是call
及 apply
的用法!
參考資料:
忍者 JavaScript 開發技巧探祕
重新認識 JavaScript: Day 20 What's "THIS" in JavaScript