apply()方法定義

函式的apply()方法和call方法作用相同,區別在於接收的引數的方式不同。
apply()方法接收兩個引數,一個是物件,一個是引數陣列。

apply()作用

1、用於延長函式的作用域

示例:

var color='red';
var o={color:'blue'};
function sayColor(){
console.log(this.color);
}
sayColor();//"red"
sayColor.apply(o);//"blue"

這裡通過apply()方法把函式動態繫結到了物件o上了,這時this指向o物件,得到結果"blue"。

2、物件不需要與方法有任何耦合關係

下面舉個耦合的例子,看如何通過apply來解決這種耦合。

var color='red';
var o={color:'blue'};
function sayColor(){
console.log(this.color);
}
o.sayColor=sayColor;
o.sayColor();//"blue"

這裡先將函式放到了物件o中,這裡物件和方法就緊耦合到一起了,方法的呼叫必須通過物件o。

沒有使用apply()和call()方法那樣靈活。
重構上面程式碼,得到前例中的程式碼。

var color='red';
var o={color:'blue'};
function sayColor(){
console.log(this.color);
}
sayColor();//"red"
sayColor.apply(o);//"blue"

這裡物件並沒有繫結任何方法,只是在需要使用的時候,利用函式的apply或call方法來動態繫結。

物件和方法之間沒有耦合在一起。這裡還可以通過ES5提供的bind()方法來完成

3、實現可變引數函式傳參

下面一個計算任意數量數字平均值的函式

average(1,2,3);
average(1);
average(3,1,2,3,5,6,7,8,9);
average(1,2,3,5,2,1,5,6,1,10);

average函式是一個稱為可變引數或可變元函式(函式的元數是指其期望的引數個數)的例子。

當然這個函式也可以寫成一個接收陣列的形式。

averageOfArray([1,2,3]);
averageOfArray([1]);
averageOfArray([3,1,2,3,5,6,7,8,9]);
averageOfArray([1,2,3,5,2,1,5,6,1,10]);

使用可變引數的函式更簡潔、優雅。可變引數函式具有便捷的語法,至少讓呼叫者預先明確地知道提供了多少個引數。

如果我有這樣一個數組

var scores=getAllScores();

如何使用average函式計算平均值呢?

1.可變引數函式版本。
這時就可以和apply()方法配合使用,這裡因為函式並沒用引用this變數,因此第一個引數我們傳入一個null。程式碼如下:

var scores=getAllScores();
average.apply(null,scores);

2.直接引數為陣列的形式

這裡可以直接傳入陣列引數。

var scores=getAllScores();
averageOfArray(scores);

以上兩種形式,個人覺得都是可以,反而第二種更簡單。多知道一種方法,對於遇到別人寫的函式時,可以輕鬆應對,不需要重構程式碼。這個好處反而更多。

4、實現可變引數方法的傳值

示例:buffer物件包含一個可變引數的append方法,該方法新增元素到函式內部的state陣列中。

var buffer={
state:[],
append:function(){
for(var i=0,n=arguments.length;i<n;i++){
this.state.push(arguments[i]);
}
}
};

這時append方法可以接受任意多個引數。

buffer.append('Hello,');
buffer.append('firtName',' ','lastName','!');
buffer.append('newLine');

形式如

buffer.append(arg1,arg2,arg3,...)

藉助apply方法的this引數,我們可以指定一個可計算的陣列呼叫append方法

buffer.append.apply(buffer,getInputStrings());

注意:這裡的buffer很重要,如果傳遞不同的物件,則append方法將嘗試修改該錯誤物件的state屬性。

提示

  • 使用apply方法指定一個可計算的引數陣列來呼叫可變引數的函式
  • 使用apply方法的第一個引數給可變引數的方法提供一個接收者

附錄一

average函式

function average(){
var args=[].slice.call(arguments);
var sum=args.reduce(function(prev,cur){
return prev+cur;
});
return parseInt(sum/args.length,10);
}

averageOfArray函式

function averageOfArray(arr){
var sum=arr.reduce(function(prev,cur){
return prev+cur;
});
return parseInt(sum/arr.length,10);
}

ES5 bind()方法

這個方法建立一個函式的例項,其this值會被繫結到傳給bind()函式的值。
例如
var color='red';
var o={color:'blue'};
function sayColor(){
console.log(this.color);
}
var oSayColor=sayColor.bind(o);
oSayColor();//"blue"

相容低版本,參考使用下面的版本

if (!Function.prototype.bind) {
Function.prototype.bind = function(oThis) {
if (typeof this !== 'function') {
// closest thing possible to the ECMAScript 5
// internal IsCallable function
throw new TypeError('Function.prototype.bind - what is trying to be bound is not callable');
} var aArgs = [].slice.call(arguments, 1),
fToBind = this,
fNOP = function() {},
fBound = function() {
return fToBind.apply(this instanceof fNOP? this: oThis,
aArgs.concat(Array.prototype.slice.call(arguments)));
}; if (this.prototype) {
// Function.prototype doesn't have a prototype property
fNOP.prototype = this.prototype;
}
fBound.prototype = new fNOP(); return fBound;
};
}