this 是执行上下文中的一个属性, 它指向最后一次调用这个方法的对象。在实际开发中, this 的指向可以通过四种调用模式来判断。
this 指向全局对象this 指向这个对象new 调用时, 函数执行前会新创建一个对象, this 指向这个新创建的对象apply、 call 和 bind 调用模式, 这三个方法都可以显示的指定调用函数的 this 指向
apply 方法接收两个参数: 一个是 this 绑定的对象, 一个是参数数组call 方法接收的参数: 一个是 this 绑定的对象, 后面的其余参数是传入函数执行的参数。也就是说, 在使用 call() 方法时, 传递给函数的参数必须逐个列举出来bind 方法通过传入一个对象, 返回一个 this 绑定了传入对象的新函数。这个函数的 this 指向除了使用 new 时会被改变, 其他情况下都不会改变这四种方式, 使用构造器调用模式的优先级最高, 然后是 apply、call 和 bind 调用模式, 然后是方法调用模式, 然后是函数调用模式。
它们的作用一模一样, 区别仅在于传入参数的形式的不同。
apply 接受两个参数, 第一个参数指定了函数体内 this 对象的指向, 第二个参数为一个带下标的集合, 这个集合可以为数组, 也可以为类数组, apply 方法把这个集合中的元素作为参数传递给被调用的函数call 传入的参数数量不固定, 跟 apply 相同的是, 第一个参数也是代表函数体内的 this 指向, 从第二个参数开始往后, 每个参数被依次传入函数call 等方式调用的情况windowFunction.prototype.myCall = function (context) {
// 判断调用对象
if (typeof this !== "function") {
console.error("type error");
}
// 获取参数
let args = [...arguments].slice(1),
result = null;
// 判断 context 是否传入, 如果未传入则设置为 window
context = context || window;
// 将调用函数设为对象的方法
context.fn = this;
// 调用函数
result = context.fn(...args);
// 将属性删除
delete context.fn;
return result;
};
call 等方式调用的情况windowFunction.prototype.myApply = function (context) {
// 判断调用对象是否为函数
if (typeof this !== "function") {
throw new TypeError("Error");
}
let result = null;
// 判断 context 是否存在, 如果未传入则为 window
context = context || window;
// 将函数设为对象的方法
context.fn = this;
// 调用方法
if (arguments[1]) {
result = context.fn(...arguments[1]);
} else {
result = context.fn();
}
// 将属性删除
delete context.fn;
return result;
};
call 等方式调用的情况apply 来绑定函数调用, 需要判断函数作为构造函数的情况, 这个时候需要传入当前函数的 this 给 apply 调用, 其余情况都传入指定的上下文对象Function.prototype.myBind = function (context) {
// 判断调用对象是否为函数
if (typeof this !== "function") {
throw new TypeError("Error");
}
// 获取参数
var args = [...arguments].slice(1),
fn = this;
return function Fn() {
// 根据调用方式, 传入不同绑定值
return fn.apply(
this instanceof Fn ? this : context,
args.concat(...arguments)
);
};
};