js中函数有三个显式更改this指向的方法,分别是apply、call以及bind方法。
至于改变this指向的其他方式,见:juejin.cn/post/697068…
三种方法的使用规则
1、三种方法的使用方式
let per1 = {
name: "Rose",
age: 14,
introduce: function(){
console.log(`我叫${this.name}, 今年${this.age}岁。`);
}
}
let per2 = {
name: "Jack",
age: 15
}
console.log(per1.introduce.call(per2)); // 我叫Jack, 今年15岁。
console.log(per1.introduce.apply(per2)); // 我叫Jack, 今年15岁。
console.log(per1.introduce.bind(per2)()); // 我叫Jack, 今年15岁。
复制代码
通过以上实例可以看出,call()
和apply()
方法是直接调用函数,而bind()
方法是生成一个函数。
如果三种方法后面使用null,则this指向全局对象,否则指向空对象(指向空对象描述可能不准确,但是这么解释很好理解)。
let per1 = {
name: "Rose",
age: 14,
introduce: function(){
console.log(`我叫${this.name}, 今年${this.age}岁。`);
}
}
window.name = "window";
window.age = 666;
console.log(per1.introduce.call(null)); // 我叫window, 今年666岁。
console.log(per1.introduce.apply(123)); // 我叫undefined, 今年undefined岁。
console.log(per1.introduce.bind("abc")()); // 我叫undefined, 今年undefined岁。
复制代码
2、三种方式的传参
let per1 = {
fn: function(fm, to){
console.log(`我来自${fm}, 即将去往${to}。`);
}
}
let per2 = {};
console.log(per1.fn.call(per2, "武汉", "杭州")); // 我来自武汉,即将去往杭州。
console.log(per1.fn.apply(per2, ["武汉", "杭州"])); // 我来自武汉,即将去往杭州。
console.log(per1.fn.bind(per2, "武汉", "杭州")()); // 我来自武汉,即将去往杭州。
console.log(per1.fn.bind(per2)("武汉", "杭州")); // 我来自武汉,即将去往杭州。
console.log(per1.fn.bind(per2, "武汉")("杭州")); // 我来自武汉,即将去往杭州。
复制代码
通过上面的示例可以看出:
call()
传参除了第一个参数,其他参数和直接使用原始方法fn()
方法传参一样,一个个将参数放进去。
apply()
方法则不同,直接传入一个数组,作为fn()
的arguments。
bind()
方法传参为,将两个函数的参数组合使用,具体可参考下文bind()
的实现方式。
三种方法的实现方式
1、call()
Function.prototype.call_ = function(obj = window, ...args) {
// 首先判断obj是否为对象,否则指向空对象
if(typeof obj !== "object" || typeof obj !== "function") {
obj = {};
}
// 给obj增加属性,避免属性名重复,使用Symbol
const fn = Symbol("fn");
obj[fn] = this;
// 执行函数
const res = obj[fn](...args);
// 清除新增的fn属性
delete obj[fn];
// 返回函数执行结果
return res;
}
复制代码
2、apply()
Function.prototype.apply_ = function(obj = window, args) {
// 首先判断obj是否为对象,否则指向空对象
if(typeof obj !== "object" || typeof obj !== "function") {
obj = {};
}
// 给obj增加属性,避免属性名重复,使用Symbol
const fn = Symbol("fn");
obj[fn] = this;
// 执行函数
const res = obj[fn](...args);
// 清除新增的fn属性
delete obj[fn];
// 返回函数执行结果
return res;
}
复制代码
3、bind()
Function.prototype.bind_ = function(obj = window, ...args) {
// 首先判断obj是否为对象,否则指向空对象
if(typeof obj !== "object" || typeof obj !== "function") {
obj = {};
}
// 通过self来保存this
const self = this;
return function F(){
// 考虑new的情况
if (this instanceof F) {
return new self(...args, ...arguments);
}
return self.apply(context, [...args, ...arguments]);
}
}
复制代码
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END