#理解call,apply,bind的用法
先说函数用法
- call——使用一个指定的 this 值和::单独给出的一个或多个参数::来::调用一个函数::
*function*.call(*thisArg*, *arg1*, *arg2*, …) - apply——::调用一个具有给定this值的函数::,以及以一::个数组(或 类数组对象 )的形式::提供的参数
*func*.apply(*thisArg, [argsArray*]) - bind ——::创建一个新的函数::,在 bind() 被调用时,这个新函数的 this 被指定为 bind() 的第一个参数,而其余参数将作为新函数的参数,供调用时使用;绑定函数自动适应于使用 new 操作符去构造一个由目标函数创建的新实例。::当一个绑定函数是用来构建一个值的,原来提供的 this 就会被忽略::。不过提供的参数列表仍然会插入到构造函数调用时的参数列表之前。
在上述用法中,我们总结一下三个函数的用法区别,call和apply在方法运行原理里的本质是相同的,只是传入的参数形式不同,都是即时调用一个给定this值的函数。bind不同于call和aplly的区别是bind不会立即调用函数,而是创建一个新的函数备份,该函数的this指向为指定的this值。特别注意的是,bind在绑定函数为构造函数的时候,函数的this指向始终指向备份函数生成的实例对象。
再说函数实现
在总结完用法后,我们对这三个函数的内部实现进行模拟。
call
Function.prototype.myCall = function (ctx) {
//当传入的对象为空时 当前函数指向为全局
if (typeof ctx == "null") {
ctx = window;
}
const ctxObj = Object(ctx);
//提取参数
const args = Array.from(arguments).slice(1);
//绑定函数到obj上
ctxObj.fn = this;
const res = ctxObj.fn(...args);
delete ctxObj.fn;
return res;
};
apply
Function.prototype.myApply = function (ctx) {
if (typeof ctx == "null") {
ctx = window;
}
const ctxObj = Object(ctx);
//提取参数
const args = arguments[1];
//绑定函数到obj上
ctxObj.fn = this;
const res = ctxObj.fn(...args);
delete ctxObj.fn;
return res;
};
bind
//生成函数备份,当调用函数为普通函数时指向传入的对象,当调用函数为构造函数时指向使用该构造函数生成的实例;
Function.prototype.myBind = function (ctx) {
if (typeof this !== "function") {
throw new Error("调用对象不是函数!!!");
}
const self = this;
//转换参数列表从类数组形式变为数组形式
const args = Array.from(arguments).slice(1);
// 生成备份函数
let fn = function () {
// 是否为实例对象
const isNew = this instanceof self;
//备份函数参数判断逻辑 以bind绑定的参数为主
const fnArgs = args.length ? args : Array.from(arguments);
return isNew ? new self(...fnArgs) : self.apply(ctx, fnArgs);
};
if (this.prototype) {
fn.prototype = this.prototype;
}
return fn;
};