call
call() 方法在使用一個指定的 this 值和若干個指定的參數(shù)值的前提下調(diào)用某個函數(shù)或方法。
舉個栗子:
var foo ={
value:1
}
function bar(){
console.log(this.value)
}
bar.call(foo);//1
需要注意兩點:
- call改變了this的指向肾胯,指向到foo;
- 調(diào)用了bar函數(shù)
模擬實現(xiàn)第一步
試想當調(diào)用 call 的時候毕荐,把 foo 對象改造成如下:
//我們希望把bar里的this指向foo艳馒;那我們把bar放進foo里面能實現(xiàn)這個效果
var foo = {
value: 1,
bar: function() {
console.log(this.value)
}
};
foo.bar(); // 1
這樣我們就實現(xiàn)了this指向foo员寇;
但是我們給foo添加了一個屬性才實現(xiàn)了這個效果蝶锋,那我們用完可以刪除掉這個屬性扳缕。
模擬步驟可分為:
// 第一步
foo.fn = bar
// 第二步
foo.fn()
// 第三步
delete foo.fn
//fn 是對象的屬性名别威,反正最后也要刪除它,所以起成什么都無所謂庸毫。
根據(jù)這個思路衫樊,我們可以嘗試著去寫第一版的 call2 函數(shù):
Function.Prototype.call2 = function(context){
//獲取調(diào)用call2的函數(shù)利花,用this
context.fn = this;
context.fn();
delete context.fn;
}
// 測試一下
var foo = {
value: 1
};
function bar() {
console.log(this.value);
}
bar.call2(foo); // 1
這樣我們就輕松模擬了call指定this指向的功能;
模擬實現(xiàn)第二步
call 函數(shù)還能給定參數(shù)執(zhí)行函數(shù)臀栈。
舉個例子:
var foo = {
value: 1
};
function bar(name, age) {
console.log(name)
console.log(age)
console.log(this.value);
}
bar.call(foo, 'Cherry', 18);
// Cherry
// 18
// 1
注意:傳入的參數(shù)并不確定挠乳,這可咋辦?
不急盟蚣,我們可以從 Arguments 對象中取值,取出第二個到最后一個參數(shù)屎开,然后放到一個數(shù)組里马靠。
比如這樣:
// 以上個例子為例,此時的arguments為:
// arguments = {
// 0: foo,
// 1: 'Cherry',
// 2: 18,
// length: 3
// }
// 因為arguments是類數(shù)組對象逞度,所以可以用for循環(huán)
var args = [];
for(var i = 1, len = arguments.length; i < len; i++) {
args.push('arguments[' + i + ']');
}
// 執(zhí)行后 args為 ["arguments[1]", "arguments[2]", "arguments[3]"]
不定長的參數(shù)問題解決了妙啃,我們接著要把這個參數(shù)數(shù)組放到要執(zhí)行的函數(shù)的參數(shù)里面去。
eval('context.fn(' + args +')')
所以我們的第二版克服了兩個大問題茁瘦,代碼如下:
// 第二版
Function.prototype.call2 = function(context) {
context.fn = this;
var args = [];
for(var i = 1, len = arguments.length; i < len; i++) {
args.push('arguments[' + i + ']');
}
eval('context.fn(' + args +')');
delete context.fn;
}
// 測試一下
var foo = {
value: 1
};
function bar(name, age) {
console.log(name)
console.log(age)
console.log(this.value);
}
bar.call2(foo, 'Cherry', 18);
// Cherry
// 18
// 1
模擬實現(xiàn)第三步
模擬代碼已經(jīng)完成 80%甜熔,還有兩個小點要注意:
1.this 參數(shù)可以傳 null,當為 null 的時候腔稀,視為指向 window
2.函數(shù)是可以有返回值的!
解決方法:
// 第三版
Function.prototype.call2 = function (context) {
var context = context || window;
context.fn = this;
var args = [];
for(var i = 1, len = arguments.length; i < len; i++) {
args.push('arguments[' + i + ']');
}
var result = eval('context.fn(' + args +')');
delete context.fn
return result;
}
// 測試一下
var value = 2;
var obj = {
value: 1
}
function bar(name, age) {
console.log(this.value);
return {
value: this.value,
name: name,
age: age
}
}
bar.call(null); // 2
console.log(bar.call2(obj, 'Cherry', 18));
// 1
// Object {
// value: 1,
// name: 'Cherry',
// age: 18
// }
到此淡喜,我們完成了 call 的模擬實現(xiàn)炼团。
文章非原創(chuàng)疏尿,有侵權(quán)請告知,文章出處:
https://github.com/mqyqingfeng/Blog/issues/11