|
|
|
|
|
.apply
和 .call
都是 Function
對象的方法:Function.apply()
、Function.call()
。
JavaScript 中的每個函數(shù)都有許多附加方法,包括toString()
、call()
和apply()
。請記住, JavaScript 中的每個函數(shù)都是一個對象。現(xiàn)在我們將關注函數(shù)的兩個方法:apply()
和call()
。
call() 方法
讓我們從以下代碼開始:
var x = 10;
function f()
{
console.log(this.x);
}
f();
輸出
10
這里我們有一個名為f()
的全局函數(shù)。f()
使用this
關鍵字來引用x
,但請注意我們不會通過對象的實例調(diào)用該函數(shù)。那么這個引用的是什么對象呢?這將引用全局對象。全局對象是我們定義變量 x
的地方。上面的代碼確實有效,并將在對話框中顯示值 10
。
call()
和apply()
都是我們可以用來在方法調(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
,因為它引用了全局對象。然而,第二次調(diào)用(通過call
方法)將顯示值 15
。15
是對象o
中x
屬性的值。call()
方法調(diào)用函數(shù)并將其第一個參數(shù)用作函數(shù)體內(nèi)的this
指針。換句話說 -我們已經(jīng)告訴運行時在函數(shù)f()
內(nèi)部執(zhí)行時引用什么對象作為this
。
我們還可以通過call()
將參數(shù)傳遞給目標函數(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()
需要一個數(shù)組作為第二個參數(shù)。該數(shù)組表示目標方法的參數(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()
方法很有用,因為我們可以構(gòu)建一個函數(shù),它不關心目標方法的簽名。該函數(shù)可以使用apply()
通過數(shù)組將所有附加參數(shù)傳遞給目標方法。
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ù)標識符
這里的問題是笨拙的語法。我們強迫調(diào)用者將參數(shù)填充到一個數(shù)組中,所以我們調(diào)用apply()
。幸運的是,有一種方法可以使語法更簡單,但我們必須再介紹一個主題:參數(shù)標識符。
在 JavaScript 中,每個函數(shù)本質(zhì)上都有一個可變長度的參數(shù)列表。這意味著即使函數(shù)只使用一個參數(shù),我們也可以將 5 個參數(shù)傳遞給函數(shù)。以下運行沒有錯誤并顯示“H”:
function f(message)
{
console.log(message);
}
f("H", "e", "l", "l", "o");
輸出
H
如果我們確實想從f()
中訪問其他參數(shù),我們可以使用 arguments 關鍵字。arguments引用了一個 Arguments 對象,該對象具有長度屬性,感覺就像一個數(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ù)組,即使它像一個數(shù)組一樣。arguments 具有長度屬性,但沒有split
、push
或pop
方法。我們可以對之前的g()
函數(shù)中的參數(shù)做的事情是將參數(shù)[1] 之后的傳入?yún)?shù)復制到我們傳遞給apply
的數(shù)組對象中。
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!
當我們調(diào)用g()
時,我們可以將其他參數(shù)作為參數(shù)傳遞,而不是將參數(shù)填充到數(shù)組中。
至此,我們已經(jīng)掌握了理解call
和apply
所需的理論知識。
那么.apply 和.call 有什么區(qū)別呢?
解釋它們差異的一個很好的助記符是:
.call
計算由逗號分隔的參數(shù)數(shù)量。
.call
方法接受一個或多個參數(shù)作為對象,并且需要明確列出,這意味著它是固定數(shù)量的參數(shù)。
foo.call(object, “other argument”, “another one”);
而
.apply
使用數(shù)組作為參數(shù)。
.apply
方法需要使用一個數(shù)組作為其第二個參數(shù)。如果你不知道要傳遞的參數(shù)數(shù)量或參數(shù)已經(jīng)在數(shù)組中,則使用此方法。
foo.apply(object, [“argument1”, “argument2”, “argument3”]);
從下面程序的注釋了解 .apply 和 .call 的區(qū)別
// .apply 和 .call 如何工作的?
/*
在這里,我們創(chuàng)建了 2 個變量,
x 變量只保存一個字符串值,
y 變量包含一個帶有 x 屬性的對象,我們稍后將使用 .call 或 .apply 方法訪問該對象
*/
var x = 'hello';
var y = {
x: 'world' };
// 我們創(chuàng)建一個標準函數(shù)
function runThis() {
console.log(this.x);
};
/*
此調(diào)用將顯示 hello 的值
因為我們在沒有新實例的情況下調(diào)用了 runThis 函數(shù)
runThis 函數(shù)中的“this”關鍵字將引用全局對象 x 的值
*/
runThis(); // 顯示 hello
/*
此調(diào)用將顯示 world 的值
因為我們使用 .call 方法調(diào)用了 runThis,
.call 方法將其第一個參數(shù)值(y 對象)用于 runThis 函數(shù)內(nèi)部的 this 關鍵字
所以在這里,我們將 y 對象引用到 'this' 關鍵字,并且
我們能夠訪問并顯示 x 屬性的值
*/
runThis.call(y); // 顯示 world
// ======================================================================
// 所以 .call 和 .apply 的區(qū)別在哪里?
/*
在這里,我們創(chuàng)建了一個名為“a”的變量,其中包含一個具有“b”屬性的對象值
*/
var a = {
b: "foo" };
/*
我們聲明了一個接受“msg”參數(shù)的函數(shù),并且
顯示與 msg 參數(shù)連接的對象的屬性值
*/
function displayMsg(msg) {
console.log(this.b + " " + msg);
}
/*
我們使用 .call 和 .apply 方法調(diào)用了 displayMsg 函數(shù)
傳入一個對象和一個參數(shù)
*/
displayMsg.call(a, "bar"); // .call 接受一個或多個對象作為它的參數(shù)
displayMsg.apply(a, ["buzz"]); // .apply 需要一個數(shù)組作為它的參數(shù)
相關文章