我遇到的问题是我创建的对象看起来像这样:
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'我做错了什么?
答案 0 :(得分:35)
当调用该函数时,“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。
答案 1 :(得分:10)
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);
}
}
}
答案 2 :(得分:3)
这是闭包的常见问题。要解决它,请尝试以下方法:
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();
}
}
答案 3 :(得分:2)
您的代码存在问题,在下面的代码行中,您定义了一个匿名函数,并将其作为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 方法作为事件处理程序。
答案 4 :(得分:2)
问题来自于如何在JS中管理this
,这可以很快,尤其是当您有异步调用的回调时(以及创建闭包时,绑定到此)。
调用AddChildRowEvents方法时,this
会很好地引用变量myObject
。但是这个方法的目的是为click提供一个处理程序。因此,该事件将在未来的某个时间触发。那时,什么对象会真正触发事件?实际上,它是用户点击的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
起可用),this
上下文不是执行上下文而是词汇上下文。两者之间的区别在于词汇上下文是在构建时而不是在执行时发现的,因此词汇上下文更容易跟踪。在arrow function
内,this
引用了外部函数的相同this
(即addEventHandler
),因此引用myObject
。
有关胖箭头功能与常规功能属性的更多说明:https://dmitripavlutin.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
时,会将this
上下文绑定到外部this
函数中的addEventHandler
元素。