Ajax Russia : Аякс по-русски

Свежие новости из мира IT

Javascript scope: что делает this?

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

JAVA:
  1. public String getName()
  2. {
  3. return this.name;
  4. }

то this будет означать инстанцию класса. В джаваскрипте это не всегда так, и это я продемонстрирую на небольшом примере.

Сделаю объект bill_gates, у которого будет name: "Bill Gates" и функция sayName(), которая будет показывать alert с именем.

JavaScript:
  1. var bill_gates = {
  2. name : "Bill Gates",
  3.  
  4. sayName : function(){ alert(this.name) }
  5. }

Также сделаю и объект steve_jobs.

JavaScript:
  1. var steve_jobs = {
  2. name : "Steve Jobs",
  3.  
  4. sayName : function(){ alert(this.name) }
  5. }

Теперь напишу маленькую функцию, которая будет принимать как параметр функцию и запускать её.

JavaScript:
  1. function runFunction(f)
  2. {
  3. f();
  4. }

Ну а теперь можно поэкспериментировать. Сначала попробуем вызвать sayName() у самого объекта.

JavaScript:
  1. bill_gates.sayName();

Всё работает. sayName() вызывается в контексте объекта bill_gates, и this это и есть сам объект bill_gates.

Теперь попробуем вызвать sayName через функцию runFunction().

JavaScript:
  1. runFunction(bill_gates.sayName);

Интересно. Alert появился, но в нём ничего нет. Это случилось потому, что мы передали только функцию sayName, и она будет запущена в глобальном контексте. Поэтому this это уже не bill_gates, а объект window.

Чтобы на экране появилось правильное имя, нужно было сделать так:

JavaScript:
  1. runFunction(bill_gates.sayName.bind(bill_gates));

Bind это особая функция прототайпа, с помощью которой можно управлять контекстом. В нашем случае мы говорим, что функцию мы хотим запустить в контексте bill_gates.

Ну и напоследок, вообще чудеса :)

JavaScript:
  1. runFunction(bill_gates.sayName.bind(steve_jobs));

Запускаем sayName у Билла Гейтса в контексте Стива Джобса. Выдаст естественно "Steve Jobs".

Надеюсь я понятно объяснил и никого не запутал. Подробнее про контекст у джаваскрипта можно почитать тут и тут.

del.icio.us Забобрить!

10 Comments so far

  1. Andrew December 5th, 2007 09:30

    эм… а если я не пользую Prototype framework?

  2. Обищенко Виталий December 5th, 2007 10:39

    А если вы не используете prototype, то можете воспользоваться, например, методом apply

    Тут подробнее:
    http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Objects:Function:apply

  3. Sam December 5th, 2007 11:36

    А кто вам вообще сказал, что в JS есть классы? Тут вообще-то прототипы. И всё ведёт себя совершенно корректно.

  4. Aleksandr December 5th, 2007 12:05

    Я не говорил, что код ведёт себя некорректно. Просто для тех, кто недавно начал работатъ с джаваскриптом - этот концепт может показаться немного странным.

  5. Andrew December 5th, 2007 12:47

    runFunction(bill_gates.sayName.apply(bill_gates)); - работает
    runFunction(bill_gates.sayName.apply(steve_jobs)); - не работает

    в чём причина?

  6. vectoroc December 5th, 2007 13:32

    Упало моё мнение о блоге…
    Такие мысли и вопросы возникают от незнания сути вопроса.
    в функцию передаётся обьект-функция (или хандл, назвать можно как угодно) без привязки к какому либо контексту.
    bind по сути лишь создаёт функцию-обёртку, которая будет делать bill_gates.sayName()

  7. vectoroc December 5th, 2007 13:39

    2 Andrew:
    оба варианта нерабочие.
    в runFunction даётся не нужная функция, а результат выполниения функции bill_gates.sayName с заданным контекстом, но, как известно, эта функция ничего не возвращает, далее выполнения скрипта завершается с ошибкой “f is not a function”

  8. Andrew December 6th, 2007 07:59

    как это не рабочие… первый вариант (в моём посте) - работает - проверено, а вот второй нет…

  9. vectoroc December 6th, 2007 11:16

    Мда, я и обьяснил в деталях, что не так. Если слов мало, вот тест, для наглядности http://victor.kolibrios.org/test_apply.htm

    rtfm как говорится

  10. Димыч July 25th, 2008 14:04

    Крутая статья. Много чего нового узнал для себя. Автору респект и уважуха :)

Leave a reply