call,apply,bind的简单实现
call, apply和bind是Function.prototype下的方法,都是可以用来改变函数运行时的上下文(this)。
call 、bind 、 apply 这三个函数的第一个参数都是 this 的指向对象(非严格模式下,第一个参数为null或undefined,指向全局对象),第二个参数不一样;
call的实现
call() 方法使用一个指定的 this 值和单独给出的一个或多个参数来调用一个函数
注意:该方法的语法和作用与 apply() 方法类似,只有一个区别,就是 call() 方法接受的是一个参数列表,而 apply() 方法接受的是一个包含多个参数的数组。
**语法:**function.call(thisArg, arg1, arg2, ...)
思路:
- 接收参数changeThis, params
- 把函数当前的上下文this,存放到changeThis的新增属性fn上
- 然后传入参数,并执行fn,得到返回结果res
- 将changeThis新增的fn属性删除
- 返回执行结果res
// 简单的实现,changeThis未做深入检测
// es6
Function.prototype._call = function (changeThis,...args) {
if (typeof this !== 'function') {
throw new TypeError('error!')
}
if (changeThis === null || changeThis === undefined) {
changeThis = window;
}
changeThis.fn = this; // 把当前的this存放到changeThis的属性上
const res = changeThis.fn(...args); // 传入参数,执行函数
delete changeThis.fn; // 删除添加的属性
return res; // 返回执行的结果
}
// 不适用es6 ,借助eval()方法实现
Function.prototype.$call = function (changeThis) {
if (typeof this !== 'function') {
throw new TypeError('error!')
}
if (changeThis === null || changeThis === undefined) {
changeThis = window;
}
changeThis.fn = this; // 把当前的this存放到changeThis的属性上
var args = [];
for (var i = 1; i < arguments.length; i++) {
args.push('arguments(' + i + ')'); // 得到参数数组
}
var res = eval('changeThis.fn(' + args + ')'); // 传入参数,执行函数
delete changeThis.fn; // 删除添加的属性
return res; // 返回执行的结果
}
apply的实现
apply() 方法调用一个具有给定this值的函数,以及作为一个数组(或类似数组对象)提供的参数。
**语法:**func.apply(thisArg, [argsArray])
思路:
- 与call的思路差不多,只是参数处理略微不同
// es6 与 call的实现类似
Function.prototype._apply = function (changeThis, params) {
if (typeof this !== 'function') {
throw new TypeError('error!')
}
if (changeThis === null || changeThis === undefined) {
changeThis = window;
}
changeThis.fn = this; // 把当前的this(即调用的对象)存放到changeThis的属性上
const fnArg = params || [];
const res = changeThis.fn(...fnArg); // 传入参数,执行函数
delete changeThis.fn; // 删除添加的属性
return res; // 返回执行的结果
}
bind的实现
bind() 方法创建一个新的函数,在 bind() 被调用时,这个新函数的 this 被指定为 bind() 的第一个参数,而其余参数将作为新函数的参数,供调用时使用。
**语法:**function.bind(thisArg[, arg1[, arg2[, ...]]])
思路:
- 缓存当前的this
- 定义一个新的函数
- 新的函数内部实现改变函数运行时的上下文的代码,并执行函数,返回执行的结果
- 新定义的函数,要继承当前上下文的原型链
- 返回该新定义的函数
Function.prototype._bind = function (changeThis, ...args) {
if (typeof this !== 'function') {
throw new TypeError('error!')
}
if (changeThis === null || changeThis === undefined) {
changeThis = window;
}
const that = this; // 缓存当前的this
const newFn = function () { // 定义需要返回的函数
// 返回函数调用,并修改this
let newThis = this instanceof newFn ? this : that;
// 借助call来改变运行时的上下文,若不需要,则使用下面注释部分的代码
const res = newThis._call(newThis, ...args);
// changeThis.fn = newThis;
// const res = changeThis.fn(newThis, ...arr);
// delete changeThis.fn;
return res;
}
if (this.prototype) {
newFn.prototype = Object.create(this.prototype); // 返回的新函数,需要继承当前this的原型链
}
return newFn; // 返回新的函数
// return 一个function
}