我们知道call,apply和bind都是用来改变this指向的内置方法,简单问就是三者的区别,复杂问就是手写实现,下面就来简单介绍下三种方法的实现。
一、call
Function.prototype._call = function (content, ...args) {
// 获取当前的执行环境,如果不存在返回window,这里相当于test._call(obj, 'bqb', '水中水')中的obj
content = content || window;
// 定义全局唯一的Symbol
let fn = Symbol();
// 在content中新增this函数,相当于test._call(obj, 'bqb', '水中水')中的test
content[fn] = this;
// 通过content[fn](...args)的方式,执行content中的方法fn,相当于,执行obj中的test,主体已经变成了obj了,例子中的this就是obj。
return content[fn](...args)
}
测试用例:
var obj = {
name: 'qb'
}
var test = function (nickName1, nickName2) {
console.log(this.name, nickName1, nickName2);
}
test._call(obj, 'bqb', '水中水')
二、apply
Function.prototype._apply = function (content, args) {
// 获取当前的执行环境,如果不存在返回window,这里相当于test._call(obj, 'bqb', '水中水')中的obj
content = content || window;
// 定义全局唯一的Symbol
let fn = Symbol();
// 在content中新增this函数,相当于test._apply(obj, 'bqb', '水中水')中的test
content[fn] = this;
// 通过content[fn](...args)的方式,执行content中的方法fn,相当于,执行obj中的test,主体已经变成了obj了,例子中的this就是obj。
return content[fn](...args)
}
测试用例:
var obj = {
name: 'qb'
}
var test = function (nickName1, nickName2) {
console.log(this.name, nickName1, nickName2);
}
test._apply(obj, ['bqb', '水中水'])
三、bind
Function.prototype._bind = function (context, ...args) {
// 获取当前的执行环境,如果不存在返回window
context = context || window;
// 定义全局唯一的Symbol
let fn = Symbol();
// 在content中新增this函数,相当于test._apply(obj, 'bqb', '水中水')中的test
context[fn] = this;
// 将当前this保存到_this中去,这里的this指的是例子中的test
var _this = this;
return function F() {
if (this instanceof F) {
// 此时this指向指向F创建的实例;
this[fn] = _this;
this[fn](...args);
delete this[fn];
} else {
// 此时的this指向传入的content;
context[fn](...args);
}
};
};
new场景测试案例:
// new场景测试案例
var obj = {
name: 'qb'
}
var test = function (nickName1, nickName2) {
this.nickName1 = nickName1;
this.nickName2 = nickName2;
}
var F = test._bind(obj, 'bqb', '水中水');
var f = new F();
直接调用场景测试案例
var obj = {
name: 'qb'
}
var test = function (nickName1, nickName2) {
console.log(this.name, nickName1, nickName2)
}
var F = test._bind(obj, 'bqb', '水中水');
F();
总结
call和apply的实现是通过content[fn] = this的方式存储当前环境,然后通过content[fn](...args)的方式调用fn方法,本着谁调用就this就指向谁的原则,this就被指向了content。bind的实现在直接调用场景和call及其apply是一致的,在new场景是通过this[fn] = _this的方式储存当前方法,然后通过this[fn](XXX)的方式调用方法,这是的this就是构造函数创建的实例。