0

При выполнении этого блока кода, выведется undefined, а не 'Вася', так как setTimeout получил метод user.sayHi, но не ее контекст:

var user = {
  firstName: "Вася",
  sayHi: function() {
    alert( this.firstName );
  }
};

setTimeout(user.sayHi, 1000); // undefined (не Вася!)

А если вызов метода обернуть в анонимную функцию, то выведется 'Вася'.

setTimeout(function() {
  user.sayHi(); // Вася
}, 1000);

Собственно возник вопрос: почему при оборачивании вызова метода в анонимную функцию, то контекст появляется?

  • Порядок вызова не перепутан? В JS действует "поднятие кода". Если не секрет, покажите весь код – DNS May 02 '17 at 16:06
  • 1
    потому что он Вы его сами написали: user. –  May 02 '17 at 16:07
  • @Igor ему ↓ стало стыдно) – Алексей Шиманский May 02 '17 at 16:13
  • @DNS https://jsfiddle.net/g5dxxfn0/ – marselbairam May 02 '17 at 16:13
  • @АлексейШиманский Ему было бы еще стыднее, если бы он знал, что ответ и комментарии все равно видны :). –  May 02 '17 at 16:14
  • Тут просто пропущены скобки setTimeout(user.sayHi(), 1000); – DNS May 02 '17 at 16:15
  • @DNS Поставьте время, скажем, 5 секунд. –  May 02 '17 at 16:17
  • @DNS так же отвечал Igor) после вызова со скобками функция setTimeout начинает работать некорректно – marselbairam May 02 '17 at 16:17
  • @Igor проверил на 5,7,10 сек. Надо больше? Все ОК – DNS May 02 '17 at 16:19
  • @Марсель - setTimeout работает нормально, просто туда подается undefined –  May 02 '17 at 16:19
  • @DNS Все не ОК. Да, надо больше. Вы чего-то не замечаете. –  May 02 '17 at 16:20
  • @Igor, я ж своими глазами вижу - ОК для 1,5,7,10 сек – DNS May 02 '17 at 16:21
  • @DNS И что, alert появляется через 10 секунд? –  May 02 '17 at 16:21
  • Не засекал.... Но пользовался платформой из ссылки. – DNS May 02 '17 at 16:23
  • @DNS https://jsfiddle.net/g5dxxfn0/1/ – marselbairam May 02 '17 at 16:24
  • @DNS Ну, разница между "десять секунд" и "мгновенно" достаточно очевидна. –  May 02 '17 at 16:24
  • Да, вспомнил, это области видимости (пространства имен). Есть поучающий пример. Сорри, праздники... Кстати, с прошедшим – DNS May 02 '17 at 16:37

2 Answers2

1

Без оборачивания в анонимную функцию this становится равен window.

var user = {
  firstName: "Вася",
  sayHi: function() {
    alert( this.firstName );
    console.log(this) // Window {}
  }
};

setTimeout(user.sayHi, 1000);

С оборачиванием this равен объекту:

var user = {
  firstName: "Вася",
  sayHi: function() {
    alert( this.firstName );
    console.log(this) // Object {firstName: "Вася"}
  }
};

setTimeout(() => user.sayHi(), 1000); 

Можно вручную установить this вызовом функции через func.call(context, arg1, arg2...)

Все дело в том, что коллбэку setTimeout передается только сама функция, без ее контекста.

useruser
  • 378
0

Используйте bind;

var user = {
  firstName: "Вася",
  sayHi: function() {
    alert( this.firstName );
  }
};

setTimeout(user.sayHi.bind(user), 1000); // undefined (не Вася!)

контекст меняется лишь потому, что контекст равен (вне случая bind) тому что написано до точки перед вызываемой функцией.

  my.pretty.good.object.method();
  //               /|\
  //----------------| контекст

если до точки ничего нет, то глобальному объекту или undefined в случае "use strict";

zb'
  • 18,100
  • не-е-ет, "еще и так" нельзя - что будет сначала, курица или яйцо? –  May 02 '17 at 16:31
  • проверил. Вы в правой части присвоения используете переменную, стоящую слева. Чему она равна в момент вызова bind? –  May 02 '17 at 16:34
  • Второй вариант не работает. Пруф: https://jsfiddle.net/830qujLy/ – Dmitriy Simushev May 02 '17 at 16:35
  • секунду, вы в общем правы, но что-то странное – zb' May 02 '17 at 16:35
  • @DmitriySimushev Не надо доказательств. Вы ведем умозрительную беседу :), академический спор - "как у Ивана Тургенева - все сидят и спорят про любовь". –  May 02 '17 at 16:35
  • @Igor, а я прагматик. Проще один раз попробовать, чем "умозрительно беседовать". – Dmitriy Simushev May 02 '17 at 16:36
  • всё разобрался, просто user у меня уже был дефайнен :) двойной вызов объявления. – zb' May 02 '17 at 16:37
  • @zb', const вам в помощь ;) – Dmitriy Simushev May 02 '17 at 16:38
  • я знаю, или let, не важно, в консоли просто слегка неудобен – zb' May 02 '17 at 16:39