丢失的 “this”
一旦方法被传递到与对象分开的某个地方———this就会丢失
let user = {
firstName: "John",
sayHi() {
alert(`Hello, ${this.firstName}!`);
}
};
/*
sayHi()是直接调用的,而不是通过对象来调用的,所以this的值丢失了
类似于
let f = user.sayHi;
setTimeout(f, 1000);
setTimeout(sayHi(){ //丢失了user的上下文
alert(`Hello, ${this.firstName}!`);
}, 1000);
*/
setTimeout(user.sayHi, 1000); // Hello, undefined!
浏览器中的 setTimeout 方法有些特殊:它为函数调用设定了 this=window(对于 Node.js,this 则会变为计时器(timer)对象,但在这儿并不重要)。所以对于 this.firstName,它其实试图获取的是 window.firstName,这个变量并不存在。在其他类似的情况下,通常 this 会变为 undefined。
解决方案1:包装器
使用一个包装函数:
let user = {
firstName: "John",
sayHi() {
alert(`Hello, ${this.firstName}!`);
}
};
//这里在外边包了一个函数,sayHi()是通过user来调用的
//this就有了值
setTimeout(function() {
user.sayHi(); // Hello, John!
}, 1000);
//简单写法
setTimeout(() => user.sayHi(), 1000); // Hello, John!
上面的写法有一个小漏洞:
如果在 setTimeout 触发之前(有一秒的延迟!)
user 的值改变了怎么办?那么,突然间,它将调用错误的对象!
let user = {
firstName: "John",
sayHi() {
alert(`Hello, ${this.firstName}!`);
}
};
setTimeout(() => user.sayHi(), 1000);
// ……user 的值在不到 1 秒的时间内发生了改变
user = {
sayHi() { alert("Another user in setTimeout!"); }
};
// Another user in setTimeout!
解决方案2:bind
func.bind(context)
func函数绑定了context对象
let user = {
firstName: "John",
sayHi() {
alert(`Hello, ${this.firstName}!`);
}
};
// user.sayHi()函数绑定了user对象
let sayHi = user.sayHi.bind(user);
// 可以在没有对象(译注:与对象分离)的情况下运行它
sayHi(); // Hello, John!
setTimeout(sayHi, 1000); // Hello, John!
// 即使 user 的值在不到 1 秒内发生了改变
// sayHi 还是会使用预先绑定(pre-bound)的值,该值是对旧的 user 对象的引用
user = {
sayHi() { alert("Another user in setTimeout!"); }
};
bindAll
如果一个对象有很多方法,并且我们都打算将它们都传递出去
那么我们可以在一个循环中完成所有方法的绑定
for (let key in user) {
if (typeof user[key] == 'function') {
user[key] = user[key].bind(user);
}
}
偏函数
bind不仅可以绑定this,还可以绑定参数(arguments)
let bound = func.bind(context, [arg1], [arg2], ...);
func绑定了context对象,且func函数第一个参数值为arg1,第二个参数值为arg2.......
function mul(a, b) {
return a * b;
}
//绑定了null,第一个参数值是2
let double = mul.bind(null, 2);
alert( double(3) ); // = mul(2, 3) = 6
alert( double(4) ); // = mul(2, 4) = 8
alert( double(5) ); // = mul(2, 5) = 10
在没有上下文情况下的partial
只想绑定参数,但是没有上下文this
partial(func, [arg1], [arg2], ...)
函数func的第一个参数是agr1,第二个参数是arg2...
// 用法:
let user = {
firstName: "John",
say(time, phrase) {
alert(`[${time}] ${this.firstName}: ${phrase}!`);
}
};
// 添加一个带有绑定时间的 partial 方法
user.sayNow = partial(user.say, new Date().getHours() + ':' + new Date().getMinutes());
user.sayNow("Hello");
// 类似于这样的一些内容:
// [10:00] John: Hello!
习题一:二次 bind
function f() {
alert(this.name);
}
f = f.bind( {name: "John"} ).bind( {name: "Ann" } );
f();
//解决方案
//答案:John。
//一个函数不能被重绑定
习题二:bind后的函数属性
函数的属性中有一个值。bind 之后它会改变吗?为什么,阐述一下?
function sayHi() {
alert( this.name );
}
sayHi.test = 5;
let bound = sayHi.bind({
name: "John"
});
alert( bound.test ); // 输出将会是什么?为什么?
//解决方案
//答案:undefined。
//bind 的结果是另一个对象。它并没有 test 属性。
本文探讨了JavaScript中因方法脱离对象导致的this丢失问题及解决方案,包括使用包装函数和bind方法,确保方法调用时能正确引用对象上下文。
丢失的this(函数绑定)&spm=1001.2101.3001.5002&articleId=110679491&d=1&t=3&u=ed389f680e9e4665adbfd5954a19d0c4)
211

被折叠的 条评论
为什么被折叠?



