40

我创建的一个看起来像这样的对象有问题:

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”我做错了什么?

4

5 回答 5

39

当函数被调用时,“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。

于 2008-12-06T07:16:34.660 回答
11

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);
        }
    }
}
于 2009-02-13T12:54:32.010 回答
9

问题来自如何this在 JS 中进行管理,这可以很快,尤其是当您异步调用回调时(以及创建闭包时,绑定到 this)。

当调用 AddChildRowEvents 方法时,this引用变量myObject。但是这个方法的目的是为点击放置一个处理程序。因此,该事件将在将来的某个时间触发。到时候,什么对象会真正触发事件呢?事实上,它是DOM element用户点击的地方。所以this将引用这个DOM element而不是myObject变量。

对于比所提供的更现代的解决方案,可以使用bind methodor arrow function

1.带箭头功能的解决方案

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 functionthis引用与this外部函数(即addEventHandler)相同的引用myObject

有关胖箭头函数与常规函数的属性的更多解释:https ://dmitripavlutin.com/6-ways-to-declare-javascript-functions/

2.绑定解决方案

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绑定到外部函数中的元素。thisthisaddEventHandler

于 2018-02-12T13:33:47.107 回答
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(); 
    }
}
于 2009-02-13T12:38:06.650 回答
2

The problem with your code is here, in the following line of code you have defined an anonymous function and passed it as an event handler for the onClick event, in the following lines:

    row.attachEvent('onclick', function(){this.DoSomething();});

and

    row.addEventListener('click', function(){this.DoSomething();}, false);

when onclick event raised and it calls the anonymous function that you have passed, this context is referring to the object that has been raised the event, but not myObject. because at this point executing context is in the event handler context.

The solution: you can do the trick that Mike Kantor has been told, or using jQuery, use the proxy method, to define this context in the anonymous function.

So your code would be like this:

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.
    }
}

you have mentioned that the error is in this.SomthingElse( ), but your code does not show it. If you really getting error at that line of code, it may you are using the method DoSomthing somewhere else as an event handler.

于 2013-08-17T07:06:39.463 回答