PDA

Просмотр полной версии : Понимание области видимости в объектно-ориентированном JS



heel
13.05.2009, 20:30
Данная статья является моим переводом!

To read this aritcle in English (http://perevodik.net/en/posts/2/)
Читати цю статтю українською мовою (http://perevodik.net/ua/posts/2/)
Читать эту статью на русском языке (http://perevodik.net/ru/posts/2/)

Когда вы думаете о ключевом слове this, вы, наверное, считаете, что оно относится к текущему экземпляру класса. Это верно для большинства объектно-ориентированных языков, как C# и Java.
Например, я мог бы использовать this в C# таким образом:



class Cat {
string _name;
public Cat(string name) {
this._name = name;
}
}


В этом примере вы можете видеть иллюстрацию этого. В C# и Java, this всегда относится к экземпляру класса.
Итак, зная это, вы наверное решите, что та же ситуация будет в JavaScript и его this. Тем не менее, это не тот случай. Как и многое в написании объектно-ориентированного кода JavaScript, this ведет себя по-разному в некоторых ситуациях. В зависимости от того как вы используете this, он может не всегда указывать на экземпляр класса.



function Cat(name) {
this.Name = name;
}


В этом примере все работает точно так же как и в примере с C#, но давайте просмотрим на пример, где вещи могут работать неправильно, если не знать некоторых правил.



var wrong = new WrongClass();
wrong.publicMethod();

function WrongClass() {
this.publicProperty = 'props';
this.publicMethod = function() {
console.log('public method');
privateMethod();
};
var privateMethod = function() {
console.log('private method');
console.log('public property equals ' + this.publicProperty);
};
}


В своих примерах, для вывода данных я использую объект console из Firebug.
Так что же не так с этим примером? Все выглядит правильно и должно работать, не так ли? Хорошо, оперируя предположением, что this всегда указывает на экземпляр класса, данный пример абсолютно верен. Тем не менее, мы используем JavaScript и не должны удивляться тому, что он делает вещи немного по-другому.
При вызове publicMethod(), было бы выведено:

>>> public method
>>> private method
>>> public property equals undefined

Причина, по которой this.publicProperty равно undefined, в том, что когда вводится приватный метод, область видимости this меняется. Оно больше не означает текущий экземпляр класса "WrongClass", теперь оно означает текущий экземпляр функции "privateMethod".
Другая ситуация, где область видимости this должно было бы поменяться, это когда оно работает с обработчиком событий.



document.getElementById('button').onclick = function() {
alert(this.id);
}


В этом примере, this будет указывать на элемент "button". Существует множество случаев изменения области видимости, с которыми вы должны быть знакомы, когда имеете дело с объектно-ориентированными технологиями.
Вернемся к нашему примеру с "WrongClass". Я покажу Вам, как сделать, чтобы этот пример работал так, как вы этого ожидали вначале.




var right = new RightClass();
right.publicMethod();

function RightClass() {
var self = this;
this.publicProperty = 'props';
this.publicMethod = function() {
console.log('public method');
privateMethod();
};
var privateMethod = function() {
console.log('private method');
console.log('public property equals ' + self.publicProperty);
};
}


Вы заметили, что я объявил в коде новую переменную self. Я присвоил этой переменной значение this. Это позволило мне использовать переменную "self" в любое время, когда мне нужно обратиться к экземпляру класса, не беспокоясь при этом про область видимости.
Вы можете назвать вашу переменную как угодно, но "self" является общей практикой. Итак, сейчас в "privateMethod", когда вызывается "publicProperty", используется "self" и оно выведет соответствующее значение.

>>> public method
>>> private method
>>> public property equals props


Understanding scope in object oriented JavaScript (http://www.geekdaily.net/2008/06/03/understanding-scope-in-object-oriented-javascript/)