Javascript scope: что делает this?
Столкнулся сегодня на работе с одной интересной особенностью джаваскрипта. Я раньше программировал на Java, и привык, что если пишешь:
-
{
-
return this.name;
-
}
то this будет означать инстанцию класса. В джаваскрипте это не всегда так, и это я продемонстрирую на небольшом примере.
Сделаю объект bill_gates, у которого будет name: "Bill Gates" и функция sayName(), которая будет показывать alert с именем.
-
var bill_gates = {
-
name : "Bill Gates",
-
-
sayName : function(){ alert(this.name) }
-
}
Также сделаю и объект steve_jobs.
-
var steve_jobs = {
-
name : "Steve Jobs",
-
-
sayName : function(){ alert(this.name) }
-
}
Теперь напишу маленькую функцию, которая будет принимать как параметр функцию и запускать её.
-
function runFunction(f)
-
{
-
f();
-
}
Ну а теперь можно поэкспериментировать. Сначала попробуем вызвать sayName() у самого объекта.
-
bill_gates.sayName();
Всё работает. sayName() вызывается в контексте объекта bill_gates, и this это и есть сам объект bill_gates.
Теперь попробуем вызвать sayName через функцию runFunction().
-
runFunction(bill_gates.sayName);
Интересно. Alert появился, но в нём ничего нет. Это случилось потому, что мы передали только функцию sayName, и она будет запущена в глобальном контексте. Поэтому this это уже не bill_gates, а объект window.
Чтобы на экране появилось правильное имя, нужно было сделать так:
-
runFunction(bill_gates.sayName.bind(bill_gates));
Bind это особая функция прототайпа, с помощью которой можно управлять контекстом. В нашем случае мы говорим, что функцию мы хотим запустить в контексте bill_gates.
Ну и напоследок, вообще чудеса
-
runFunction(bill_gates.sayName.bind(steve_jobs));
Запускаем sayName у Билла Гейтса в контексте Стива Джобса. Выдаст естественно "Steve Jobs".
Надеюсь я понятно объяснил и никого не запутал. Подробнее про контекст у джаваскрипта можно почитать тут и тут.
del.icio.us Забобрить!10 Comments so far
Leave a reply
эм… а если я не пользую Prototype framework?
А если вы не используете prototype, то можете воспользоваться, например, методом apply
Тут подробнее:
http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Objects:Function:apply
А кто вам вообще сказал, что в JS есть классы? Тут вообще-то прототипы. И всё ведёт себя совершенно корректно.
Я не говорил, что код ведёт себя некорректно. Просто для тех, кто недавно начал работатъ с джаваскриптом - этот концепт может показаться немного странным.
runFunction(bill_gates.sayName.apply(bill_gates)); - работает
runFunction(bill_gates.sayName.apply(steve_jobs)); - не работает
в чём причина?
Упало моё мнение о блоге…
Такие мысли и вопросы возникают от незнания сути вопроса.
в функцию передаётся обьект-функция (или хандл, назвать можно как угодно) без привязки к какому либо контексту.
bind по сути лишь создаёт функцию-обёртку, которая будет делать bill_gates.sayName()
2 Andrew:
оба варианта нерабочие.
в runFunction даётся не нужная функция, а результат выполниения функции bill_gates.sayName с заданным контекстом, но, как известно, эта функция ничего не возвращает, далее выполнения скрипта завершается с ошибкой “f is not a function”
как это не рабочие… первый вариант (в моём посте) - работает - проверено, а вот второй нет…
Мда, я и обьяснил в деталях, что не так. Если слов мало, вот тест, для наглядности http://victor.kolibrios.org/test_apply.htm
rtfm как говорится
Крутая статья. Много чего нового узнал для себя. Автору респект и уважуха