call和apply的模擬實現

2022-09-16 03:24:11 字數 3318 閱讀 1809

一句話介紹 call:

call() 方法在使用乙個指定的 this 值和若干個指定的引數值的前提下呼叫某個函式或方法。

舉個例子:

var foo = ;

function bar()

bar.call(foo); // 1

注意兩點:

call 改變了 this 的指向,指向到 foo

bar 函式執行了

那麼我們該怎麼模擬實現這兩個效果呢?

試想當呼叫 call 的時候,把 foo 物件改造成如下:

var foo = 

};foo.bar(); // 1

這個時候 this 就指向了 foo,是不是很簡單呢?

但是這樣卻給 foo 物件本身新增了乙個屬性,這可不行吶!

不過也不用擔心,我們用 delete 再刪除它不就好了~

所以我們模擬的步驟可以分為:

將函式設為物件的屬性

執行該函式

刪除該函式

以上個例子為例,就是:

// 第一步

foo.fn = bar

// 第二步

foo.fn()

// 第三步

delete foo.fn

fn 是物件的屬性名,反正最後也要刪除它,所以起成什麼都無所謂。

根據這個思路,我們可以嘗試著去寫第一版的 call2 函式:

// 第一版

function.prototype.call2 = function(context)

// 測試一下

var foo = ;

function bar()

bar.call2(foo); // 1

正好可以列印 1 哎!是不是很開心!(~ ̄▽ ̄)~

最一開始也講了,call 函式還能給定引數執行函式。舉個例子:

var foo = ;

function bar(name, age)

bar.call(foo, 'kevin', 18);

// kevin

// 18

// 1

注意:傳入的引數並不確定,這可咋辦?

不急,我們可以從 arguments 物件中取值,取出第二個到最後乙個引數,然後放到乙個陣列裡。

比如這樣:

// 以上個例子為例,此時的arguments為:

// arguments =

// 因為arguments是類陣列物件,所以可以用for迴圈

var args = ;

for(var i = 1, len = arguments.length; i < len; i++)

// 執行後 args為 ["arguments[1]", "arguments[2]", "arguments[3]"]

不定長的引數問題解決了,我們接著要把這個引數陣列放到要執行的函式的引數裡面去。

// 將陣列裡的元素作為多個引數放進函式的形參裡

context.fn(args.join(','))

// (o_o)??

// 這個方法肯定是不行的啦!!!

也許有人想到用 es6 的方法,不過 call 是 es3 的方法,我們為了模擬實現乙個 es3 的方法,要用到es6的方法,好像……,嗯,也可以啦。但是我們這次用 eval 方法拼成乙個函式,類似於這樣:

eval('context.fn(' + args +')')

這裡 args 會自動呼叫 array.tostring() 這個方法。

所以我們的第二版克服了兩個大問題,**如下:

// 第二版

function.prototype.call2 = function(context)

eval('context.fn(' + args +')');

delete context.fn;

}// 測試一下

var foo = ;

function bar(name, age)

bar.call2(foo, 'kevin', 18);

// kevin

// 18

// 1

模擬**已經完成 80%,還有兩個小點要注意:

1.this 引數可以傳 null,當為 null 的時候,視為指向 window

舉個例子:

var value = 1;

function bar()

bar.call(null); // 1

雖然這個例子本身不使用 call,結果依然一樣。

2.函式是可以有返回值的!

舉個例子:

var obj = 

function bar(name, age)

}console.log(bar.call(obj, 'kevin', 18));

// object

不過都很好解決,讓我們直接看第三版也就是最後一版的**:

// 第三版

function.prototype.call2 = function (context)

var result = eval('context.fn(' + args +')');

delete context.fn

return result;

}// 測試一下

var value = 2;

var obj =

function bar(name, age)

}bar.call(null); // 2

console.log(bar.call2(obj, 'kevin', 18));

// 1

// object

到此,我們完成了 call 的模擬實現,給自己乙個贊 b( ̄▽ ̄)d

var context = object(context) || window;

context.fn = this;

var result;

if (!arr)

else

result = eval('context.fn(' + args + ')')

}delete context.fn

return result;

}

5 模擬實現call和apply

1 先來看call的乙個例子 1 var value 1 2var foo 56 function bar 910 bar.call foo 1 猜想 假設在執行call的時候,把bar函式新增到foo物件下,執行foo.bar,具體如下 1 var foo 6 78 foo.bar 1 這就是我們...

js模擬實現call和apply方法

call 方法在使用乙個指定的 this 值和若干個指定的引數值的前提下呼叫某個函式或方法。例子 var foo function bar bar.call foo 2從這個例子中可以看出兩點 上述例子試想當呼叫 call 的時候,把 foo 物件改造成如下 var foo foo.bar 2這個時...

js中call和apply的模擬實現

示例 call的正常使用 var key windowk var obj function fn name,age fn lucy 20 name lucy age 20 this.key windowk fn.call obj,lucy 20 name lucy age 20 this.key o...