call函數(shù)的使用方式如下:
var obj = {
value: 1
};
function foo(name, age) {
console.log(this.value);
console.log(name);
console.log(age);
}
foo.call(obj, 'aaa', 12); // 1 aaa 12
首先我們要知道call函數(shù)都有哪些功能:
1. 改變了this的指向惩坑,讓它指向obj
2. 函數(shù)foo執(zhí)行
3. 允許傳入?yún)?shù),且參數(shù)個(gè)數(shù)不確定
4. 允許第一個(gè)參數(shù)context為null
5. 執(zhí)行后的返回值為函數(shù)執(zhí)行后的返回值
如何實(shí)現(xiàn)this指向obj呢,參考對(duì)象內(nèi)部函數(shù)定義,如果fn是obj的方法屬性恕稠,那么就this就指向了obj,然后執(zhí)行函數(shù)扶欣,之后再刪除函數(shù)鹅巍,這就實(shí)現(xiàn)了前兩步。
Function.prototype.call2 = function (context){
context.fn = this;
context.fn();
delete context.fn;
}
如何允許傳入?yún)?shù)料祠,用到arguments骆捧,要將參數(shù)一個(gè)個(gè)傳入context.fn,只能動(dòng)態(tài)拼接執(zhí)行髓绽,考慮用eval敛苇,eval能將string字符串作為js執(zhí)行的函數(shù)。
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;
}
如何允許第一個(gè)參數(shù)可以為null梧宫,驗(yàn)證context是否存在接谨,context默認(rèn)為window對(duì)象。即?context = context || window
如何允許有返回值塘匣,將函數(shù)的執(zhí)行結(jié)果用result變量存儲(chǔ)脓豪,返回result即可。最終代碼如下:
Function.prototype.call2 = function (context){
context = context || window;
context.fn = this;
var args = [];
for(var i = 1, len = arguments.length; i < len; i++) {
args.push('arguments[' + i + ']');
}
const result = eval('context.fn('+ args + ')');
delete context.fn
return result
}
const fn = function(name, age) {
console.log(this.value);
return {
name: name,
age: age
};
}
const obj = {
value: 'obj'
}
var value = 'window';
fn.call(null); //'window'
const result = fn.call2(obj, '小明', 12); // 'obj'
console.log(result.age); //12
apply函數(shù)的功能和call基本一致忌卤,區(qū)別在于只有兩個(gè)參數(shù)扫夜,第一個(gè)參數(shù)是context,第二個(gè)是函數(shù)參數(shù)數(shù)組驰徊。實(shí)現(xiàn)和call一致笤闯,實(shí)現(xiàn)代碼如下:
Function.prototype.apply = function(context, arr) {
var ctx = context || window;
ctx.fn = this;
var result;
if (!arr) {
result = ctx.fn();
} else {
var args = [];
for (var i = 0, len = arr.length; i < len; i++) {
args.push('arr[' + i + ']');
}
result = eval('ctx.fn(' + args + ')');
}
delete ctx.fn;
return result;
};