本篇文章来自各种文章的总结,主要是用自己的话总结一下,加深印象。面试官问:能否模拟实现JS的call和apply方法
Call 和 apply 的实现
call和apply都是在使用后,返回绑定了新的this的function的执行结果。那么,简单的实现,便是在绑定的obj身
上创建我们将要执行的function,在执行完之后,删除这个function,并返回结果。
apply实现
// 浏览器环境 非严格模式
function getGlobalObject(){
return this;
}
Function.prototype.applyFn = function apply(thisArg, argsArray){
//因为apply是function上的方法,由function调用,那么this便是调用的function
if(typeof this !== 'function'){
throw new TypeError(this + ' is not a function');
}
//如果传入的第二个参数为空,就用空数组代替
if(typeof argsArray === 'undefined' || argsArray === null){
argsArray = [];
}
// 如果第二个参数,不是个obj的东西,抛出异常。这里写入数组,也是可以通过这个!==检测的。
if(argsArray !== new Object(argsArray)){
throw new TypeError('CreateListFromArrayLike called on non-object');
}
//如果没有传入需要绑定的对象,那么会默认使用最高层的。对于浏览器环境,就是window对象。
if(typeof thisArg === 'undefined' || thisArg === null){
thisArg = getGlobalObject();
}
thisArg = new Object(thisArg);
//这里建议使用随机数或者时间戳这种东西命名,而不是__fn。避免在原来的对象上存在重名的
var __fn = '__fn';
thisArg[__fn] = this;
var result = thisArg[__fn](...argsArray);
delete thisArg[__fn];
return result;
};
call实现
call和apply最明显的区别就是,call需要将函数所需参数,一一填写,apply可以通过数组传入。那么实现了apply之后,便可以调用apply来实现call
Function.prototype.callFn = function call(thisArg){
var argsArray = [];
var argumentsLength = arguments.length;
for(var i = 0; i < argumentsLength - 1; i++){
argsArray[i] = arguments[i + 1];
}
return this.applyFn(thisArg, argsArray);
}
bind实现
Function.prototype.bind = function (context) {
//调用的函数本身
var me = this;
//把传入的参数都写入
var argsArray = Array.prototype.slice.callFn(arguments);
//返回一个新的函数,该函数在执行时候,会返回以传入的context为this来运行调用的函数的结果
return function () {
return me.applyFn(context, argsArray.slice(1))
}
}