|
|
|
|
|
.apply
和 .call
都是 Function
對(duì)象的方法:Function.apply()
、Function.call()
。
JavaScript 中的每個(gè)函數(shù)都有許多附加方法,包括toString()
、call()
和apply()
。請(qǐng)記住, JavaScript 中的每個(gè)函數(shù)都是一個(gè)對(duì)象?,F(xiàn)在我們將關(guān)注函數(shù)的兩個(gè)方法:apply()
和call()
。
call() 方法
讓我們從以下代碼開始:
var x = 10;
function f()
{
console.log(this.x);
}
f();
輸出
10
這里我們有一個(gè)名為f()
的全局函數(shù)。f()
使用this
關(guān)鍵字來(lái)引用x
,但請(qǐng)注意我們不會(huì)通過(guò)對(duì)象的實(shí)例調(diào)用該函數(shù)。那么這個(gè)引用的是什么對(duì)象呢?這將引用全局對(duì)象。全局對(duì)象是我們定義變量 x
的地方。上面的代碼確實(shí)有效,并將在對(duì)話框中顯示值 10
。
call()
和apply()
都是我們可以用來(lái)在方法調(diào)用期間分配this
指針的方法。例如,下面是我們?nèi)绾问褂?code>call()方法:
var x = 10;
var o = { x: 15 };
function f()
{
console.log(this.x);
}
f();
f.call(o);
輸出
10
15
f()
的第一次調(diào)用將顯示值 10
,因?yàn)樗昧巳謱?duì)象。然而,第二次調(diào)用(通過(guò)call
方法)將顯示值 15
。15
是對(duì)象o
中x
屬性的值。call()
方法調(diào)用函數(shù)并將其第一個(gè)參數(shù)用作函數(shù)體內(nèi)的this
指針。換句話說(shuō) -我們已經(jīng)告訴運(yùn)行時(shí)在函數(shù)f()
內(nèi)部執(zhí)行時(shí)引用什么對(duì)象作為this
。
我們還可以通過(guò)call()
將參數(shù)傳遞給目標(biāo)函數(shù):
var x = 10;
var o = { x: 15 };
function f(message)
{
console.log(message);
console.log(this.x);
}
f("invoking f");
f.call(o, "invoking f via call");
執(zhí)行結(jié)果
apply() 方法
apply()
方法與call()
相同,只是 apply()
需要一個(gè)數(shù)組作為第二個(gè)參數(shù)。該數(shù)組表示目標(biāo)方法的參數(shù)。
var x = 10;
var o = { x: 15 };
function f(message)
{
console.log(message);
console.log(this.x);
}
f("invoking f");
f.apply(o, ["invoking f through apply"]);
執(zhí)行結(jié)果
apply()
方法很有用,因?yàn)槲覀兛梢詷?gòu)建一個(gè)函數(shù),它不關(guān)心目標(biāo)方法的簽名。該函數(shù)可以使用apply()
通過(guò)數(shù)組將所有附加參數(shù)傳遞給目標(biāo)方法。
var o = { x: 15 };
function f1(message1)
{
console.log(message1 + this.x);
}
function f2(message1, message2)
{
console.log(message1 + (this.x * this.x) + message2);
}
function g(object, func, args)
{
func.apply(object, args);
}
g(o, f1, ["the value of x = "]);
g(o, f2, ["the value of x squared = ", ". Wow!"]);
執(zhí)行結(jié)果
參數(shù)標(biāo)識(shí)符
這里的問(wèn)題是笨拙的語(yǔ)法。我們強(qiáng)迫調(diào)用者將參數(shù)填充到一個(gè)數(shù)組中,所以我們調(diào)用apply()
。幸運(yùn)的是,有一種方法可以使語(yǔ)法更簡(jiǎn)單,但我們必須再介紹一個(gè)主題:參數(shù)標(biāo)識(shí)符。
在 JavaScript 中,每個(gè)函數(shù)本質(zhì)上都有一個(gè)可變長(zhǎng)度的參數(shù)列表。這意味著即使函數(shù)只使用一個(gè)參數(shù),我們也可以將 5 個(gè)參數(shù)傳遞給函數(shù)。以下運(yùn)行沒(méi)有錯(cuò)誤并顯示“H”:
function f(message)
{
console.log(message);
}
f("H", "e", "l", "l", "o");
輸出
H
如果我們確實(shí)想從f()
中訪問(wèn)其他參數(shù),我們可以使用 arguments 關(guān)鍵字。arguments引用了一個(gè) Arguments 對(duì)象,該對(duì)象具有長(zhǎng)度屬性,感覺(jué)就像一個(gè)數(shù)組。
function f(message)
{
// message param is the same as arguments[0]
for(var i = 1; i < arguments.length; i++)
{
message += arguments[i];
}
console.log(message);
}
// this will say "Hello"
f("H", "e", "l", "l", "o");
輸出
Hello
正如你所知,arguments 在技術(shù)上不是一個(gè)數(shù)組,即使它像一個(gè)數(shù)組一樣。arguments 具有長(zhǎng)度屬性,但沒(méi)有split
、push
或pop
方法。我們可以對(duì)之前的g()
函數(shù)中的參數(shù)做的事情是將參數(shù)[1] 之后的傳入?yún)?shù)復(fù)制到我們傳遞給apply
的數(shù)組對(duì)象中。
var o = { x: 15 };
function f(message1, message2)
{
console.log(message1 + (this.x * this.x) + message2);
}
function g(object, func)
{
// arguments[0] == object
// arguments[1] == func
var args = []; // empty array
// copy all other arguments we want to "pass through"
for(var i = 2; i < arguments.length; i++)
{
args.push(arguments[i]);
}
func.apply(object, args);
}
g(o, f, "The value of x squared = ", ". Wow!");
輸出
The value of x squared = 225. Wow!
當(dāng)我們調(diào)用g()
時(shí),我們可以將其他參數(shù)作為參數(shù)傳遞,而不是將參數(shù)填充到數(shù)組中。
至此,我們已經(jīng)掌握了理解call
和apply
所需的理論知識(shí)。
那么.apply 和.call 有什么區(qū)別呢?
解釋它們差異的一個(gè)很好的助記符是:
.call
計(jì)算由逗號(hào)分隔的參數(shù)數(shù)量。
.call
方法接受一個(gè)或多個(gè)參數(shù)作為對(duì)象,并且需要明確列出,這意味著它是固定數(shù)量的參數(shù)。
foo.call(object, “other argument”, “another one”);
而
.apply
使用數(shù)組作為參數(shù)。
.apply
方法需要使用一個(gè)數(shù)組作為其第二個(gè)參數(shù)。如果你不知道要傳遞的參數(shù)數(shù)量或參數(shù)已經(jīng)在數(shù)組中,則使用此方法。
foo.apply(object, [“argument1”, “argument2”, “argument3”]);
從下面程序的注釋了解 .apply 和 .call 的區(qū)別
// .apply 和 .call 如何工作的?
/*
在這里,我們創(chuàng)建了 2 個(gè)變量,
x 變量只保存一個(gè)字符串值,
y 變量包含一個(gè)帶有 x 屬性的對(duì)象,我們稍后將使用 .call 或 .apply 方法訪問(wèn)該對(duì)象
*/
var x = 'hello';
var y = {
x: 'world' };
// 我們創(chuàng)建一個(gè)標(biāo)準(zhǔn)函數(shù)
function runThis() {
console.log(this.x);
};
/*
此調(diào)用將顯示 hello 的值
因?yàn)槲覀冊(cè)跊](méi)有新實(shí)例的情況下調(diào)用了 runThis 函數(shù)
runThis 函數(shù)中的“this”關(guān)鍵字將引用全局對(duì)象 x 的值
*/
runThis(); // 顯示 hello
/*
此調(diào)用將顯示 world 的值
因?yàn)槲覀兪褂?nbsp;.call 方法調(diào)用了 runThis,
.call 方法將其第一個(gè)參數(shù)值(y 對(duì)象)用于 runThis 函數(shù)內(nèi)部的 this 關(guān)鍵字
所以在這里,我們將 y 對(duì)象引用到 'this' 關(guān)鍵字,并且
我們能夠訪問(wèn)并顯示 x 屬性的值
*/
runThis.call(y); // 顯示 world
// ======================================================================
// 所以 .call 和 .apply 的區(qū)別在哪里?
/*
在這里,我們創(chuàng)建了一個(gè)名為“a”的變量,其中包含一個(gè)具有“b”屬性的對(duì)象值
*/
var a = {
b: "foo" };
/*
我們聲明了一個(gè)接受“msg”參數(shù)的函數(shù),并且
顯示與 msg 參數(shù)連接的對(duì)象的屬性值
*/
function displayMsg(msg) {
console.log(this.b + " " + msg);
}
/*
我們使用 .call 和 .apply 方法調(diào)用了 displayMsg 函數(shù)
傳入一個(gè)對(duì)象和一個(gè)參數(shù)
*/
displayMsg.call(a, "bar"); // .call 接受一個(gè)或多個(gè)對(duì)象作為它的參數(shù)
displayMsg.apply(a, ["buzz"]); // .apply 需要一個(gè)數(shù)組作為它的參數(shù)
相關(guān)文章