[英]Javascript Closures and 'this'
我创建的一个对象有问题,它看起来像这样:
var myObject = {
AddChildRowEvents: function(row, p2) {
if(document.attachEvent) {
row.attachEvent('onclick', function(){this.DoSomething();});
} else {
row.addEventListener('click', function(){this.DoSomething();}, false);
}
},
DoSomething: function() {
this.SomethingElse(); //<-- Error here, object 'this' does not support this method.
}
}
问题是,当我在“DoSomething”函数中时,“this”不是指“myObject”,我做错了什么?
当函数被调用时,“this”指的是行。 如果你想拥有这个对象,你可以这样做:]
AddChildRowEvents: function(row, p2) {
var theObj = this;
if(document.attachEvent) {
row.attachEvent('onclick', function(){theObj.DoSomething();});
} else {
row.addEventListener('click', function(){theObj.DoSomething();}, false);
}
},
当函数被调用时,它可以访问定义函数时在作用域内的变量 theOBj。
this
总是指内部函数,如果您有嵌套函数,则必须创建另一个变量并将其指向this
。
var myObject = {
AddChildRowEvents: function(row, p2) {
var that = this;
if(document.attachEvent) {
row.attachEvent('onclick', function(){that.DoSomething();});
} else {
row.addEventListener('click', function(){that.DoSomething();}, false);
}
}
}
问题来自在 JS 中如何管理this
,它可以很快,尤其是当您异步调用回调时(并且当创建一个闭包时,绑定到 this)。
当调用 AddChildRowEvents 方法时, this
很好地引用了变量myObject
。 但是这个方法的目的是为点击放置一个处理程序。 所以该事件将在未来的某个时间触发。 那个时候,什么对象会真正触发事件? 事实上,它是用户将点击的DOM element
。 所以this
将引用这个DOM element
而不是myObject
变量。
对于比所提供的更现代的解决方案,可以使用bind method
或arrow function
。
let handler = { addEventHandler: function(row) { console.log("this", this) row.addEventListener("click", () => { console.log("this", this) this.doSomethingElse() }) }, doSomethingElse: function() { console.log("something else") } } var div = document.querySelector("div") handler.addEventHandler(div)
<div>one</div>
使用arrow function
(自ES2015
起ES2015
), this
上下文不是执行上下文,而是词法上下文。 两者之间的区别在于词法上下文是在构建时而不是在执行时找到的,因此词法上下文更容易跟踪。 这里,在arrow function
内部, this
引用了外部函数(即addEventHandler
)的相同this
,因此引用myObject
。
有关胖箭头函数与常规函数的属性的更多解释: https : //dmittripavlutin.com/6-ways-to-declare-javascript-functions/
let handler = { addEventHandler: function(row) { console.log("this", this) row.addEventListener("click", function() { console.log("this", this) this.doSomethingElse() }.bind(this)) }, doSomethingElse: function() { console.log("something else") } } var div = document.querySelector("div") handler.addEventHandler(div)
<div>one</div>
这一次,当回调函数传递给addEventListener
,在addEventHandler
函数外部将this
上下文绑定到this
元素。
这是闭包的常见问题。 要解决它,请尝试以下操作:
var myObject = {
AddChildRowEvents: function(row, p2) {
var self = this;
if(document.attachEvent) {
row.attachEvent('onclick', function(){this.DoSomething(self);});
} else {
row.addEventListener('click', function(){this.DoSomething(self);}, false);
}
},
DoSomething: function(self) {
self.SomethingElse();
}
}
您的代码的问题就在这里,在以下代码行中,您定义了一个匿名函数并将其作为 onClick 事件的事件处理程序传递,在以下几行中:
row.attachEvent('onclick', function(){this.DoSomething();});
和
row.addEventListener('click', function(){this.DoSomething();}, false);
当 onclick 事件引发并调用您传递的匿名函数时,此上下文指的是引发事件的对象,而不是myObject 。 因为此时执行上下文在事件处理程序上下文中。
解决方案:您可以按照 Mike Kantor 所说的技巧,或者使用 jQuery,使用代理方法,在匿名函数中定义此上下文。
所以你的代码会是这样的:
var myObject = {
AddChildRowEvents: function(row, p2) {
if(document.attachEvent) {
row.attachEvent('onclick', $.proxy(function () {
this.DoSomething();
}, this));
} else {
row.addEventListener('click', $.proxy(function () {
this.DoSomething();
},this), false);
}
},
DoSomething: function() {
this.SomethingElse(); //<-- Error here, object 'this' does not support this method.
}
}
您已经提到错误在this.SomthingElse() 中,但是您的代码没有显示它。 如果您确实在该行代码中遇到错误,则可能是您在其他地方使用DoSomthing方法作为事件处理程序。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.