call\apply\bind实现原理解析
fn.call方法原理
Function.prototype.v2call = function (thisArg, ...args) {
//目的:将传入的thisArg对象作为调用v2call的函数的this指向
//使用fn变量存储this 此时fn指向调用v2call的函数对象 这里是foo
var fn = this;
//边界判断 如果不为空 将原始字面量转化为实例对象 否则thisArg指向window
thisArg = thisArg ? Object(thisArg) : window;
//thisArg新增fn属性引用函数对象fn
thisArg.fn = fn;
args = !isNone(args) ? args : [];
//隐式绑定: 函数在不同上下文调用时会影响this的指向
//此时在thisArg上下文中调用时fn的this会绑定thisArg
var res = thisArg.fn(...args);
//做完删除fn
delete thisArg.fn;
//返回函数调用的返回值
return res;
};
function isNone(v) {
return v === undefined || v === null
}
var a = '这是全局的a';
function foo() {
console.log('this指向:', this);
var sum = Array.prototype.reduce.call(
arguments,
(pre, cur) => {
return pre + cur;
},
0
);
console.log('value:', sum);
return sum;
}
var obj = {
a: '这是obj对象里的a',
};
console.log(foo.v2call(obj, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10));
输出结果:
77b30a406e58d0308b71d80082b59889
fn.apply方法原理
Function.prototype.v2apply = function (thisArg, args) {
//目的:将传入的thisArg对象作为调用v2call的函数的this指向
//使用fn变量存储this 此时fn指向调用v2call的函数对象 这里是foo
var fn = this;
//边界判断 如果不为空 将原始字面量转化为实例对象 否则thisArg指向window
thisArg = thisArg ? Object(thisArg) : window;
//关键: 利用隐式绑定: 函数的调用方式会影响this的指向
//thisArg新增fn属性引用函数对象fn
thisArg.fn = fn;
//此时在thisArg上下文中调用时fn的this会绑定thisArg
args = !isNone(args) ? args : [];
var res = thisArg.fn(...args);
//做完删除fn
delete thisArg.fn;
//返回函数调用的返回值
return res;
};
function isNone(v) {
return v === undefined || v === null
}
var a = '这是全局的a';
function foo() {
console.log('this指向:', this);
var sum = Array.prototype.reduce.call(
arguments,
(pre, cur) => {
return pre + cur;
},
0
);
console.log('value:', sum);
return sum;
}
var obj = {
a: '这是obj对象里的a',
};
console.log(foo.v2apply(obj, [1, 2, 3, 4,5]));
输出结果:
d03c30e655d8b1c70bf2ae93c27ca630
fn.bind 方法原理
Function.prototype.v2bind = function (thisArg, ...argsArr) {
//目的:将传入的thisArg对象作为调用v2call的函数的this指向,并返回这个函数,且传入的参数可先固定
//使用fn变量存储this 此时fn指向调用v2call的函数对象 这里是foo
var fn = this;
//边界判断 如果不为空 将原始字面量转化为实例对象 否则thisArg指向window
thisArg = thisArg ? Object(thisArg) : window;
function proxyFn(...args) {
thisArg.fn = fn;
var concatParams = [...argsArr, ...args];
//隐式绑定: 函数在不同上下文调用时会影响this的指向
//此时在thisArg上下文中调用时fn的this会绑定thisArg
var res = thisArg.fn(...concatParams);
//调用完删除fn
delete thisArg.fn;
//返回fn返回值
return res;
}
//返回这个绑定this后的函数
return proxyFn;
};
function isNone(v) {
return v === undefined || v === null;
}
var a = '这是全局的a';
function foo() {
console.log('this指向:', this);
var sum = Array.prototype.reduce.call(
arguments,
(pre, cur) => {
return pre + cur;
},
0
);
console.log('value:', sum);
return sum;
}
var obj = {
a: '这是obj对象里的a',
};
var bindFn = foo.v2bind(obj, 1, 2, 3, 4, 5);
console.log(bindFn);
console.log(bindFn(6, 7, 8, 9, 10));
输出结果:
ca844c6114193b8dea5d05161ddae1f8