# call apply bind模拟实现
call()
方法使用一个指定的 this
值和单独给出的一个或多个参数来调用一个函数。
TIP
备注:该方法的语法和作用与 apply()
(opens new window) 方法类似,只有一个区别,就是 call()
方法接受的是一个参数列表,而 apply()
方法接受的是一个包含多个参数的数组。
# call
采用rest参数实现
Function.prototype.call2 = function (context, ...args) {
// 传入null时, 指向为window
context = context || window;
context.func = this;
const result = context.func(...args);
delete context.func;
return result;
};
采用arguments 配合eval实现
Function.prototype.call3 = function (context) {
// 传入null时, 指向为window
context = context || window;
context.func = this;
const args = [];
for (let i = 1, len = arguments.length; i < len; i++) {
args.push('arguments[' + i + ']');
}
const result = eval('context.func(' + args + ')');
delete context.func;
return result;
};
# apply
apply相对简单
Function.prototype.apply2 = function (context, params) {
// 传入null时, 指向为window
context = context || window;
context.func = this;
const args = [];
let result;
if (!params) {
result = context.func();
} else {
if (!Array.isArray(params)) {
throw new TypeError('Expect an array param');
}
for (let i = 0, len = params.length; i < len; i++) {
args.push('params[' + i + ']');
}
result = eval('context.func(' + args + ')');
}
delete context.func;
return result;
};
# bind
bind()
方法创建一个新的函数,在 bind()
被调用时,这个新函数的 this
被指定为 bind()
的第一个参数,而其余参数将作为新函数的参数,供调用时使用。
Function.prototype.bind2 = function (context) {
const args = Array.prototype.slice.call(arguments, 1);
const callback = this;
const Noop = function () {};
const newFunction = function () {
const bindArgs = Array.prototype.slice.call(arguments);
// 当作为构造函数时,this 指向实例,此时结果为 true,将绑定函数的 this 指向该实例,可以让实例获得来自绑定函数的值
// 当作为普通函数时,this 指向 window,此时结果为 false,将绑定函数的 this 指向 context
return callback.apply(
this instanceof Noop ? this : context,
args.concat(bindArgs)
);
};
// 防止原型污染
Noop.prototype = callback.prototype;
newFunction.prototype = new Noop();
return newFunction;
};
简便一点, 采用rest参数不考虑原型实现
Function.prototype.bind3 = function (context, ...args) {
const callback = this;
return function (...args2) {
return callback.apply(context, args.concat(args2));
};
};
再用rest参数配合箭头函数实现一点
const bind4 =
(callback, context, ...args) =>
(...args2) => {
return callback.call(context, ...args, ...args2);
};