前言
Javascript中改变this指向的方法有call、apply、bind。它们都可以改变this的指向,但是也有一些不同。本文会讲解一下它们之间的区别。以及如何模拟实现cal、apply、bind方法
一、call、apply、bind的区别
call、apply、bind区别很简单
1. call调用时改变this的指向,第一个参数是需要改变this指向的目标,后面参数为函数调用所需参数
var person = {
firstName: "Lee",
lastName: "Jordan",
};
function getFullName(separator) {
return `${this.firstName}${separator}${this.lastName}`;
}
// 如果需要传入第三个参数 可以在“-”加逗号后添加, 依次累加 例如 getFullName.call(person, "-", argument)
console.log(getFullName.call(person, "-"));
2. apply调用时改变this的指向,第一个参数也是 需要改变this指向的目标,第二参数为一个函数调用所需参数的数据
var person = {
firstName: "Lee",
lastName: "Jordan",
};
function getFullName(separator) {
return `${this.firstName}${separator}${this.lastName}`;
}
// call 和 apply 的区别 一个是以参数占位方式传递函数需要的参数 一个是一个参数列表数组的形式给到函数
console.log(getFullName.call(person, ["-"]));
3. bind调用时改变this的指向并且返回一个新的函数, this的指向将不能再次更改。第一次调用时第一个参数是需要改变this指向的目标,后面的参数会合并。具体看看例子。
// 第一次绑定的this是this value 后续再使用call\apply\bind都无法改变thi的指向
// 每次绑定的第二位参数开始后面的参数将会合并 1 2 3 4 5 6
function log(...args) {
console.log(this, ...args);
}
const boundLog = log.bind("this value", 1, 2);
const boundLog2 = boundLog.bind("new this value", 3, 4);
boundLog2(5, 6); // [String: 'this value'] 1 2 3 4 5 6
二、模拟实现call
Function.prototype.selfCall = function (thisArg, ...args) {
// 判定绑定目标的边界
var thisArg =
thisArg === null || thisArg === undefined ? globalThis : Object(thisArg);
var fn = this;
thisArg.fn = fn;
const result = thisArg.fn(...args);
delete thisArg.fn;
return result;
};
三、模拟实现apply
Function.prototype.selfApply = function (thisArg, args) {
var args = args === undefined ? [] : args,
fn = this;
if (!Array.isArray(args)) {
throw new Error("参数类型不对");
}
var thisArg =
thisArg === null || thisArg === undefined ? globalThis : Object(thisArg);
thisArg.fn = fn;
const result = thisArg.fn(...args);
delete thisArg.fn;
return result;
};
四、模拟实现bind
Function.prototype.selfBind = function (thisArg, ...argsArray) {
var _this = this;
var context =
thisArg === null || thisArg === undefined ? globalThis : Object(thisArg);
return function fn(...args) {
const allArgs = [...argsArray, ...args];
// 防止new的调用
if (this instanceof fn) {
return new _this(...allArgs);
}
// 普通函数的调用
return _this.apply(context, allArgs);
};
};
总结
本文主要讲了call/apply/bind的区别,以及模拟实现了call/apply/bind方法。模拟的这些方法还有一些边界没有判断。发现了可以在上述代码基础上添加。结束收工!