Javascript闭包和'这个'

时间:2008-12-06 06:31:38

标签: javascript closures

我遇到的问题是我创建的对象看起来像这样:

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

5 个答案:

答案 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 methodarrow 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 function内,this引用了外部函数的相同this(即addEventHandler),因此引用myObject

有关胖箭头功能与常规功能属性的更多说明:https://dmitripavlutin.com/6-ways-to-declare-javascript-functions/

2。带有bind的解决方案

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元素。