Задать вопрос
@BlackSSA

И снова this в javascript?

Народ, объясните, пожалуйста, для тупого про this в javascript на пальцах! Сколько уже бьюсь, понимание никак не приходит! Читаю в доках, что в js this зависит от контекста вызова. Ок, пишу код:
function f(){
    console.log(this);
}

var o = {
    f1:function(f2){
        console.log(this);//object
        f2();//Window
        f();//Window
    },
    f11: f
}

o.f1(f)

В 7-ой строке убеждаюсь, что контекст действительно объекта o
8-ая строка... Опаньки! Читал-же, что зависит от контекста вызова! Как так? Контекст - о, а в this - window? При этом в 11-ой строке все норм, как и написано в учебниках - в this действительно o.

Объясните, пожалуйста!!! Пишу код, но отсутствие понимания вымораживает! Хелп!
  • Вопрос задан
  • 643 просмотра
Подписаться 2 Простой Комментировать
Решения вопроса 1
AngReload
@AngReload
Кратко о себе
На пальцах: когда ты пишешь через точку вот так - объект.метод() то this метода будет равен объекту. Если точки перед функцией нет, то this === Window.
Ответ написан
Пригласить эксперта
Ответы на вопрос 3
IonDen
@IonDen
JavaScript developer. IonDen.com
У Кантора же прекрасно и подробно расписано: https://learn.javascript.ru/object-methods

И постарайтесь давать нормальные имена функциям и переменным, гораздо легче запутаться в сокращениях чем в нормальных названиях.

В вашем случае:
function foo(){
    console.log(this); // на данный момент не определен
}

var obj = {
    bar: function(baz){
        console.log(this); // функция вызвана в контексте объекта - obj.bar()
        baz(); // функция просто вызвана внутри другой фукнции, т.е. без контекста
        foo(); // тоже самое
    }
}

obj.bar(foo);

// Если же очень хочется принудительно передать контекст, то:
foo.call(obj);
Ответ написан
Комментировать
Xuxicheta
@Xuxicheta
инженер
Обычные функции используют контекст с которым они были вызваны
Стрелочные функции используют конекст в котором они были вызваны.
Дергая просто f() - контекст не указан и функции передается глобальный объект.
Вот, посмотрите jsfiddle.net/cbw5qnkz
и вот jsfiddle.net/g3kbfaj7/1
Ответ написан
@BlackSSA Автор вопроса
Ребята, всем-всем огромное спасибо! По-моему, после 1000-го раза прочтения Ильи Кантора и перепиской с форумчанами понял! Под "контекстом вызова" понимается простой вызов метода! Я, ошибочно, отождествлял контекст со scope! А оказалось все проще). Напишу для таких-же, как я(если они существуют и основным направлением является что-то типа C# ;)), javascript-кодерам лучше не читать ))) :
В javascript "контекст вызова" = экземпляру класса, в котором вызван метод. Т.к. глобальный инстанс в web javascript = window, то все функции (в javascript функции и методы - ЭТО РАЗНЫЕ ВЕЩИ!!! Вернее, по мне, так js-"функции" - это те-же методы объекта window, но в документации они разделяются) вызываются под ним. Т.е., если в коде есть:
function foo()//учел правильную критику Дениса Ишенина с наименованиями
{
    console.log(this);
}

то это равнозначно в шарпе:
class Window{
public ... Foo(...)
}

и соответственно вызов в js в любом месте кода
...
foo();
...

хоть внутри метода, хоть в внутри другой функции, хоть "в корне" кода - "контекстом вызова"(инстансом по нашему в C#) будет естественно Window. При этом, как ни странно, не важно, где определять функцию! В js ее (именно функцию, а не метод!!!) можно определить даже внутри метода! И она все-равно будет инстансом Window! Ну вот например:
var foo = {
    someFunc: function(){
        ...
        function innerFunction(){
            console.log(this);
        }
        innerFunction();
    }
}

угадайте, что выведет innerFunction? Правильно, "Window"!
Но есть несколько "но"(как-же без них )):
1) Если написать "use strict" вначале кода или этой функции, то будет совсем не Window, а undefine
2) В js метод одного инстанса(1) можно вызвать в другом инстансе(2)(соответственно этот вызов будет видеть переменные этого самого другого инстанса(2)) с помощью bind и т.д.. Мне сложно провести аналогию с C#.
3) Пока не разобрался с "потерей контекста", но, думаю, завтра на свежую голову, с пониманием, что такое "контекст вызова" - разберусь.
4) Есть еще "стрелочные функции", но с ними, как ни странно у меня проблем не возникло. )
P.S. прав был дяденька Декарт, когда сказал, что половину споров на земле не существовало бы, если бы люди знали смысл слов, о которых они спорят ))) Наконец-то я для себя понял(надеюсь, что правильно), как это работает! Два года писал код "как надо", и вот сегодня отважился задать вопрос и благодаря ответам наконец-то разобрался "почему". Еще раз всем огромное спасибо!
P.P.S. Коллега подсказал, что еще проще понять(и я с ним согласен), если везде, где нет точки при объявлении/вызове функции мысленно писать Window. Т.е., вместо
function foo()
{
    console.log(this);
}

в голове сразу строится конструкция
function Window.foo()//учел правильную критику Дениса Ишенина с наименованиями
{
    console.log(this);
}
,
а вместо
var foo = {
    someFunc: function(){
        ...
        function innerFunction(){
            console.log(this);
        }
        innerFunction();
    }
}

строится
var foo = {
    someFunc: function(){
        ...
        function Window.innerFunction(){
            Window.console.log(this);
        }
        Window.innerFunction();
    }
}

и тогда инстанс, он-же "контекст вызова" - очевиден ;).
Еще, kova1ev подсказал в коментах первого ответа про потерю контекста. Рекомендую его ответ, мне он помог!
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы