Javascript闭包和'这个'

34 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.
    }
}
Run Code Online (Sandbox Code Playgroud)

问题是当我进入'DoSomething'函数时,'this'不会引用'myObject'我做错了什么?

Mik*_*tor 36

当函数被调用时,"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);
    }
},
Run Code Online (Sandbox Code Playgroud)

调用该函数时,它可以访问定义函数时在范围内的变量theobj.

  • 我花了一段时间才得到它 - 原因是 row.attachEvent 将一个事件附加到该行,当该事件触发时,该行就是调用该函数的行(它可能会执行类似 f.apply(this, args ))。我对么? (2认同)

svi*_*nto 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);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)


pom*_*421 7

问题来自thisJS 中的管理方式,可以很快,尤其是当您异步调用回调时(并且在创建闭包时,绑定到此)。

当调用 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)
Run Code Online (Sandbox Code Playgroud)
<div>one</div>
Run Code Online (Sandbox Code Playgroud)

使用arrow function(自 以来可用ES2015),this上下文不是执行上下文,而是词法上下文。两者之间的区别在于词法上下文是在构建时而不是在执行时找到的,因此词法上下文更容易跟踪。这里,内侧的arrow functionthis引用相同的this外部功能(即,addEventHandler),以便参考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)
Run Code Online (Sandbox Code Playgroud)
<div>one</div>
Run Code Online (Sandbox Code Playgroud)

这一次,当回调函数传递给 时addEventListener,已经将this上下文绑定到this外部addEventHandler函数中的元素。