Как Javascript оператор «this» работает с областями действия? - PullRequest
2 голосов
/ 18 октября 2010

Редактировать: Я должен извиниться, проблема, о которой я писал, на самом деле не существует в коде, который я разместил, потому что я упростил его.Я постараюсь опубликовать что-нибудь позже.

Удаление тоже будет в порядке, но сейчас слишком много ответов, поэтому я не могу сделать это сам.

Edit2: Хорошо, вот что:

Позвольте,

function F() {

    this.field = "value" ;

    var init = function(value) {
        this.field = value ;
    } ;

    this.method = function() {
        return this.field ;
    } ;

    init( arguments[0] ) ;

} 

Теперь, экземпляр типа F,

var f = new F("newValue") ;

установит значение Windowобъект как this указывает на него при вызове из замыкания.

Привязка this к Function,

function F() {

    var self = this ;

    this.field = "value" ;

    var init = function(value) {
        self.field = value ;
    } ;

    this.method = function() {
        return this.field ;
    } ;

    init( arguments[0] ) ;

}

решит проблему.

И все же, в чем причина этого - странного поведения?

Ответы [ 5 ]

2 голосов
/ 18 октября 2010

Это (ссылка) на объект, для которого была вызвана функция.

Таким образом, в вашем вызове f.method(), this - это "f".НЕ "F".

Тот факт, что var self = this; работает, объясняется не самим этим утверждением, а тем, что method2() является замыканием

Более конкретно, переменная self внутри method2() имеет область действия, определяемую F() - другими словами, «self» внутри method2() ВСЕГДА будет ссылаться на значение selfкоторый существовал, когда было определено «F» (которое в то время, конечно, было «F», поскольку в тот момент текущий контекст объекта был «F»).

1 голос
/ 20 октября 2010

Как оказалось, это один из темных углов спецификации ECMA для ECMAScript (отсюда и JavaScript):

Наконец, значение назначено для использования с ключевым словом this. Если присвоенное значение относится к объекту, то средства доступа к свойствам с префиксом this ссылаются на свойства этого ключевого слова. Если назначенное (внутренне) значение равно нулю, ключевое слово this будет ссылаться на глобальный объект.

(http://jibbering.com/faq/notes/closures/; спасибо @ Brian Flanagan за ссылку)

Очевидно, что во время выполнения функции, которая назначена переменной (внутри другого Function), контекст теряется, таким образом, область видимости устанавливается равной нулю, и this будет ссылаться на Window Object.


Я не совсем уверен, стоит ли ожидать чего-то от Function, инициализированного как локальная переменная. Обычно я ожидаю, что у замыкания будет доступ к области, в которой оно было создано, пока оно находится в памяти, включая его предшественника в цепочке областей.

Это поведение отличается от функции, которая является свойством Function Object, где контекст не потерян и this будет правильно указывать на владельца элемента Function (который является Function Object или членом в зависимости от количества слоев).


Решением этой проблемы (при сохранении частных Function членов, то есть членов, которые доступны только из области действия Function) является обертывание функции внутри другого Function с использованием Function.prototype.apply (или * 1035) *) чтобы установить контекст вручную:

function F() {

    this.field = "value" ;

    var self = this ;

    var init = function(value) {

        (function() {
            this.field = value ;
        }).apply(self,value) ;

    } ;

    this.method = function() {
        return this.field ;
    } ;

    init( arguments[0] ) ;

} 

Это аналогично Function.prototype.bind, представленному в JavaScript 1.85, а также библиотеке PrototypeJS.

Редактировать: Забыл скобки вокруг вложенной функции в init. Это приведет к SyntaxError.

1 голос
/ 18 октября 2010

Это тот пример, который вы искали?

var F = function() {

     var self = this ; //!! points correctly to the Function Object

     this.field = "someValue" ;

     var helper1 = function(){
         return self.field;
     }
     var helper2 = function(){
         return this.field;  
     } 
     this.method = function(){
         return helper1();
     }
     this.method2 = function(){
         return helper2();
     }
 }

 var f = new F() ;
     console.log(f.method()) ; 
     console.log(f.method2()) ; 

В случае метода он вызывает helper, который использует self, который указывает на f при создании и, следовательно, работает.

В случае method2 он использует helper2, который использует это. Но значение этого, находящегося внутри helper2, является «глобальной» областью и, следовательно, возвращает неопределенное значение.

1 голос
/ 18 октября 2010

Для определения метода вы, вероятно, захотите сделать что-то более похожее на:

this.method = function()
{
    return this.field;
}
1 голос
/ 18 октября 2010

Неправильно называть this "оператором".Это ссылка на объект, устанавливаемая средой выполнения после активации функции.

Javascript - это просто другой язык, который делает вещи по-разному.То, что this находится под контролем программиста, удивительно мощно.

Также этот код определенно не работает, если что-то еще, что вы не опубликовали, не устанавливает объект-прототип для «F».Ни «method», ни «method2» не могут быть вызваны из ссылки на экземпляр «F».

...