Подтвердить что ты не робот

Закрытие Javascript и '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", что я делаю неправильно?

4b9b3361

Ответ 1

Когда функция вызывается, "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, которая была в области видимости, когда функция была определена.

Ответ 2

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);
        }
    }
}

Ответ 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(); 
    }
}

Ответ 4

Проблема с вашим кодом здесь, в следующей строке кода вы определили анонимную функцию и передали ее как обработчик события для события onClick в следующих строках:

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

и

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

когда событие onclick поднято и вызывает анонимную функцию, которую вы передали, этот контекст ссылается на объект, который был поднят, но не myObject. потому что в этот момент исполняемый контекст находится в контексте обработчика события.

Решение: вы можете сделать трюк, о котором сказал Майк Кантор, или используя 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.
    }
}

вы упомянули, что ошибка в этом. SomthingElse(), но ваш код не показывает его. Если вы действительно получаете ошибку в этой строке кода, возможно, вы используете метод DoSomthing где-то еще как обработчик событий.

Ответ 5

Проблема связана с тем, как this управляется в JS, что может быть быстро, особенно когда вы вызываете асинхронно обратный вызов (и когда создается ограничение, привязанное к этому).

Когда вызывается метод AddChildRowEvents, this хорошо ссылается на переменную myObject. Но целью этого метода является установка обработчика щелчка. Таким образом, событие будет запущено в будущем. В то время какой объект действительно инициирует событие? Фактически, это DOM element на который пользователь щелкнет. Таким образом, this будет ссылка на этот DOM element а не на переменную myObject.

Для более современного решения, чем представленные, можно использовать bind method или 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>