<-Home
实现函数的 call、apply、 bind 方法
1. call
call() 方法在使用一个指定的 this 值和若干个指定的参数值的前提下调用某个函数或方法。
function.call(thisArg, arg1, arg2, …)
thisArg 参数在非严格模式下时,如果指定为 null 或者 undefined,则会被替换为全局对象,原始值会被包装;
call 实现
/** 实现思路
1. 将函数做为属性赋值给context,注意context可能是null或者 undefeind,兼容为window或者global
2. 取arguments第一个到最后一个作为函数调用参数,使用eval执行得到结果
3. 删除context赋值的函数属性
4. 返回eval执行得到的结果
**/
Function.prototype.call2 = function(context) {
context = context || window || global;
context.fn = this;
var args = [];
for (var index = 1; index < args.length; index++) {
args.push('arguments[' + index + ']');
}
var result = eval('context.fn(' + args + ')');
// 上的参数取用逻辑可以使用es6语法代替
// var result = context.fn(...[...arguments].splice(1))
delete context.fn;
return result;
}
2. apply
apply 和 call的区别在于传递参数的方式不同
apply 实现
Function.prototype.apply2 = function(context, arr) {
context = context || window || global;
context.fn = this;
var result;
if (!arr) result = context.fn();
else {
var args = [];
for (var index = 1; index < args.length; index++) {
args.push('arguments[' + index + ']');
}
result = eval('context.fn(' + args + ')');
}
delete context.fn;
return result;
}
3. bind
bind()会创建一个新的函数。当这个函数被调用时,bind()的第一个参数作为运行时的this,之后的一系列参数将会在运行时传递的实参前作为它的参数。
bind的实现
Function.prototype.bind2 = function(context) {
if(typeof this !== 'function') {
throw new Error('Function.prototype.bind to be bound must be a function');
}
var self = this;
var args = Array.prototype.slice.call(arguments, 1);
// fNOP -> a functoin not own prototype
var fNOP = function() {}
var fBound = function() {
var bindArgs = Array.prototype.slice.call(arguments);
// 普通函数使用时this 指向 window
// new 方式构造函数使用时,this 指向 fBound
// 不同的方式导致 apply 指向的this不同
return self.apply(this instanceof fNOP ? this : context, args.concat(bindArgs));
}
// 以下的方式避免了在修改fBound函数的原型时同时修改绑定函数的原型
fNOP.prototype = this.prototype;
fBound.prototype = new fNOP();
return fBound;
}