從經(jīng)典案例中認(rèn)識call(),apply(),bind()

目錄

  • function基礎(chǔ)
  • apply(context,[arg1,arg2])
    • 獲取數(shù)組中最大的值
    • 使用push合并數(shù)組
    • 模擬construct構(gòu)造器方法
  • call(context,arg1,arg2)
    • 類數(shù)組對象的數(shù)組方法操作
    • uncurrying 反柯里化
  • bind(context)

function基礎(chǔ)

在ECMAScript中函數(shù)是對象,因此函數(shù)也有屬性和方法。[1]

1.屬性

  • length
    參數(shù)數(shù)量
  • prototype
    指向函數(shù)的所有實(shí)例方法,換句話說,諸如toString()valueOf()(返回函數(shù)的代碼) 都保存在prototype名下

2.方法

每個函數(shù)都包含兩個非繼承而來(即不在prototype名下)的方法apply()call()

apply(context,[arg1,arg2,...])

apply()方法接收兩個參數(shù):一個是在其中運(yùn)行的函數(shù)作用域,另一個可以是arguments也可以是自定義Array的實(shí)例。
經(jīng)典案例
- 獲取數(shù)組中最大的值

var arr = [1,2,3,4,9,8,7,5]
var result = Math.max.apply(null,a rr)

- 使用push合并數(shù)組

var arr1 = [1,2,3]
var arr2 = [4,5,6]
Array.prototype.push.apply(arr2,arr1);
console.log(arr2) //[4,5,6,1,2,3]

- 模擬construct構(gòu)造器方法

Function.prototype.construct = function(){
  var oNew = Object.create(this.prototype);
  this.apply(oNew, arguments);
  return oNew;
}

call(context,arg1,arg2,arg3,...)

call()apply()用法相同,只是除了第一個都是作用域之外,其余參數(shù)必須逐個列舉出來,即 使用call()方法時必須明確要傳多少參數(shù),同樣也可以先創(chuàng)建函數(shù)之后再利用call確定參數(shù)。
經(jīng)典案例
- 對類數(shù)組對象進(jìn)行一系列數(shù)組的方法操作
類數(shù)組對象{0:'asd',1:123,2:{},length:3},最經(jīng)典的就是arguments對象

[].shift.call(arguments)  //刪除arguments中的第一個參數(shù)并返回這個參數(shù)

//詳情解釋
var a = {0:1,1:2,2:3,length:3};
console.log([].shift.call(a)) // 1
console.log( a )  // {0: 2, 1: 3, length: 2}

- 使用call調(diào)用父構(gòu)造函數(shù)實(shí)現(xiàn)繼承

function Parent(name, age){
  this.name = name;
  this.age = age;
}

function Son(name, age, weight){
  Parent.call(name, age) //繼承Parent函數(shù)的name和age屬性
  this.weight = weight //私有屬性
}

var son = new Son('Niko', 24, 140)
console.log(son)  // Son {name:'Niko', age:24, weight:140}

- 使用call調(diào)用匿名函數(shù)

const arr = [0,1,2,3,4]
for(let i=0; i<arr.length; i++){
  (function(i){
    //...
    console.log(i) // 0,1,2,3,4
  }).call(arr, i)
}

- ??修改上下文this指向

var name = 'Niko'
function func(){ console.log(this.name) }
var obj = {
  name : 'Bellic'
}
func.call(obj) // Bellic
func();  // Niko

- uncurrying反柯里化 [2]

我們常常讓類數(shù)組對象去借用Array.prototype的方法,這是call和apply最常用的應(yīng)用場景之一:

(function(){
  Array.prototype.push.call( arguments, 4 ); // arguments借用Array.prototype.push方法
  console.log( arguments ); // [1, 2, 3, 4]
})(1, 2, 3)

在我們的預(yù)期中,Array.prototype上的方法原本只能用來操作array對象。但用call和apply可以把任意對象當(dāng)作this傳入某個方法,這樣一來,方法中用到this的地方就不再局限于原來規(guī)定的對象,而是加以泛化并得到更廣的適用性。

那么如何將泛化this過程提取出來呢?
uncurrying()函數(shù)實(shí)現(xiàn)

Function.prototype.uncurrying = function(){
  var self = this;
  return function(){
    var obj = Array.prototype.shift.call( arguments );
    return self.apply( obj, arguments )
  }
}

bind(context)

bind()方法會創(chuàng)建一個函數(shù)的實(shí)例,其this值會被綁定傳遞給bind()函數(shù)的值。

Function.prototype.bind = function(context){
  var self = this;        //保存原函數(shù)
  return function(){    // 返回一個新函數(shù)
    return self.apply( context, arguments )
  }
}

總結(jié)

它們真正強(qiáng)大的地方是能夠擴(kuò)充函數(shù)賴以運(yùn)行的作用域

參考

- [1]《JavaScript高級程序設(shè)計(jì)》(第3版) p.116 函數(shù)屬性和方法
- [2] 《JavaScript設(shè)計(jì)模式與開發(fā)實(shí)踐》 p.51 高階函數(shù)
- 上述部分案例參考自https://developer.mozilla.org/

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容