iT邦幫忙

2019 iT 邦幫忙鐵人賽

DAY 9
0
自我挑戰組

學JS的心路歷程系列 第 9

學JS的心路歷程 Day9- 函式(四) apply、call

  • 分享至 

  • xImage
  •  

從上一篇可以知道,不同的函式呼叫會造成 this 的不同,但我們能不能在呼叫時候明確指定呢?

當然可以。會有這個想法是因為往往在執行某支函式時想要用回呼函式,但發現 this 總是顯示 window ,為了確保 this 是我們想要的物件或函式,就必須使用 applycall

可能有點難以理解,這邊我們來看一個範例:

var obj = {
	price : 20,
	sum : function (cb){
		cb(100);
	}
}

function getData(val){
	console.log(this);
}

obj.sum(getData);//Window

可以看到我們預期 getDatathisobj 物件,但顯示出來的卻是 window

這是因為,當沒有特定指明 this 的情況下,預設綁定 (Default Binding) this 為 「全域物件」,也就是 window

所以除非我們透過 callapply 強制指定 this 為自己想要的物件或函式,不然 getData 都會是預設的 window

就算包裹在物件內也是一樣:

var obj = {
	price : 20,
	sum : function (cb){
		cb(100);
	},
    getData : function (val){
        console.log(this,val);
    }
}
obj.sum(obj.getData);//Window

好,現在我們知道callapply 可以強制指定 this了,那要怎麼用呢?
callapply 的作用完全一樣,差別只在傳入參數的方式有所不同。
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);
    }
  }
}

以上就是callapply 的用法!

參考資料:
忍者 JavaScript 開發技巧探祕
重新認識 JavaScript: Day 20 What's "THIS" in JavaScript


上一篇
學JS的心路歷程 Day8 -函式(三) this
下一篇
學JS的心路歷程 Day10-函式(五)箭頭函式
系列文
學JS的心路歷程30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言