Javascript "this" указатель внутри вложенной функции

У меня вопрос о том, как обработчик "this" обрабатывается в сценарии вложенных функций.

Скажем, я вставляю этот следующий пример кода в веб-страницу. Я получаю сообщение об ошибке, когда я вызываю вложенную функцию "doSomeEffects()". Я проверил в Firebug, и это указывает, что когда я нахожусь в этой вложенной функции, указатель "this" фактически указывает на глобальный объект "window", чего я не ожидал. Я не должен правильно понимать что-то, потому что я думал, что, поскольку я объявил вложенную функцию внутри функции объекта, она должна иметь "локальную" область действия по отношению к функции (т.е. Указатель "this" будет ссылаться на сам объект, например как это в моем первом выражении "если" ).

Любые указатели (не предназначенные для каламбуров) будут оценены.

var std_obj = {
  options : { rows: 0, cols: 0 },
  activeEffect : "none",
  displayMe : function() {

    // the 'this' pointer is referring to the std_obj
    if (this.activeEffect=="fade") { }

    var doSomeEffects = function() {

      // the 'this' pointer is referring to the window obj, why?
      if (this.activeEffect=="fade") { }

    }

    doSomeEffects();   
  }
};

std_obj.displayMe();

Ответ 1

В JavaScript объект this действительно основан на том, как вы выполняете вызовы функций.

Как правило, существует три способа установки объекта this:

  • someThing.someFunction(arg1, arg2, argN)
  • someFunction.call(someThing, arg1, arg2, argN)
  • someFunction.apply(someThing, [arg1, arg2, argN])

Во всех приведенных выше примерах объект this будет someThing. Вызов функции без ведущего родительского объекта обычно будет вам глобальным объектом, который в большинстве браузеров означает объект window.

Ответ 2

this не является частью области закрытия, его можно рассматривать как дополнительный параметр для функции, связанной с сайтом вызова. Если метод не вызывается как метод, глобальный объект передается как this. В браузере глобальный объект идентичен window. Например, рассмотрим следующую функцию:

function someFunction() {
}

и следующий объект

var obj = { someFunction: someFunction };

Если вы вызываете функцию с использованием синтаксиса метода, например,

obj.someFunciton();

то this привязан к obj.

Если вы вызываете someFunction() напрямую, например

someFunction();

то this привязан к глобальному объекту, то есть window.

Наиболее распространенная работа заключается в том, чтобы зафиксировать это в закрытии, например,

displayMe : function() {      

    // the 'this' pointer is referring to the std_obj      
    if (this.activeEffect=="fade") { }      
    var that = this;  
    var doSomeEffects = function() {      

      // the 'this' pointer is referring to global
      // that, however, refers to the outscope this
      if (that.activeEffect=="fade") { }      
    }      

    doSomeEffects();         
 }      

Ответ 3

Поскольку это, по-видимому, относится к числу наиболее распространенных вопросов такого рода, позвольте мне добавить все эти годы решение ES6 с использованием функций стрелок:

var std_obj = {
  ...
  displayMe() {
    ...
    var doSomeEffects = () => {
                        ^^^^^^^    ARROW FUNCTION    
      // In an arrow function, the 'this' pointer is interpreted lexically,
      // so it will refer to the object as desired.
      if (this.activeEffect=="fade") { }
    };
    ...    
  }
};

Ответ 4

Существует разница между переменными окружения и "this". "this" фактически определяется вызовом функции, в то время как явные переменные остаются неповрежденными внутри блока объявления функции, известного как оболочка. См. Пример ниже:

function myFirstObject(){
    var _this = this;
    this.name = "myFirstObject";
    this.getName = function(){
       console.log("_this.name = " + _this.name + " this.name = " + this.name);  
    }
}

function mySecondObject(){
    var _this = this;
    this.name = "mySecondObject";
    var firstObject = new myFirstObject();
    this.getName = firstObject.getName
}

var secondObject = new mySecondObject();
secondObject.getName();

вы можете попробовать: http://jsfiddle.net/kSTBy/

Что происходит в вашей функции - "doSomeEffects()", вызывается явно, это означает, что контекст или "this" функции - это окно. если "doSomeEffects" был прототипом, например. this.doSomeEffects on say "myObject", тогда myObject.doSomeEffects() вызовет "this" как "myObject".

Ответ 5

Чтобы понять этот вопрос, попробуйте получить вывод для следующего фрагмента

var myObject = {
    foo: "bar",
    func: function() {
        var self = this;
        console.log("outer func:  this.foo = " + this.foo);
        console.log("outer func:  self.foo = " + self.foo);
        (function() {
            console.log("inner func:  this.foo = " + this.foo);
            console.log("inner func:  self.foo = " + self.foo);
        }());
    }
};
myObject.func();

Приведенный выше код выведет на консоль следующее:

outer func:  this.foo = bar
outer func:  self.foo = bar
inner func:  this.foo = undefined
inner func:  self.foo = bar

Во внешней функции, как это, так и самостоятельно ссылаются на myObject, и поэтому оба могут правильно ссылаться и получать доступ к foo.

Во внутренней функции это больше не относится к myObject. В результате this.foo является undefined во внутренней функции, тогда как ссылка на локальную переменную self остается в области видимости и доступна там. (До ECMA 5 это во внутренней функции относится к глобальному объекту окна, тогда как по ECMA 5 это во внутренней функции будет undefined.)

Ответ 6

Как объяснил Кайл, вы можете использовать call или apply для указания this внутри функции:

Вот эта концепция, применяемая к вашему коду:

var std_obj = {
    options: {
        rows: 0,
        cols: 0
    },
    activeEffect: "none",
    displayMe: function() {

        // the 'this' pointer is referring to the std_obj
        if (this.activeEffect == "fade") {}

        var doSomeEffects = function() {
            // the 'this' pointer is referring to the window obj, why?
            if (this.activeEffect == "fade") {}
        }

        doSomeEffects.apply(this,[]);
    }
};

std_obj.displayMe();

JsFiddle