繁体   English   中英

Javascript 闭包和“这个”

[英]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 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 (自ES2015ES2015 ), this上下文不是执行上下文,而是词法上下文。 两者之间的区别在于词法上下文是在构建时而不是在执行时找到的,因此词法上下文更容易跟踪。 这里,在arrow function内部, this引用了外部函数(即addEventHandler )的相同this ,因此引用myObject

有关胖箭头函数与常规函数的属性的更多解释: https : //dmittripavlutin.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 ,在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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM