Javascript указатель «this» внутри вложенной функции - PullRequest
78 голосов
/ 10 марта 2012

У меня есть вопрос относительно того, как указатель this обрабатывается в сценарии с вложенными функциями.

Скажем, я вставил следующий пример кода на веб-страницу. Я получаю сообщение об ошибке при вызове вложенной функции doSomeEffects (). Я проверил в Firebug, и это указывает, что, когда я нахожусь в этой вложенной функции, указатель «this» фактически указывает на глобальный объект «окна» - чего я не ожидал. Я не должен понимать что-то правильно, потому что я думал, что, поскольку я объявил вложенную функцию внутри функции объекта, она должна иметь «локальную» область видимости по отношению к функции (то есть указатель «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();

Ответы [ 6 ]

110 голосов
/ 10 марта 2012

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

Обычно существует три способа настройки объекта this:

  1. someThing.someFunction(arg1, arg2, argN)
  2. someFunction.call(someThing, arg1, arg2, argN)
  3. someFunction.apply(someThing, [arg1, arg2, argN])

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

28 голосов
/ 10 марта 2012

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();         
 }      
27 голосов
/ 10 апреля 2016

Поскольку это один из самых популярных вопросов в своем роде, позвольте мне добавить после всех этих лет решение 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") { }
    };
    ...    
  }
};
10 голосов
/ 10 марта 2012

Есть разница между переменными вложения и "этим".«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 ()", вызывается явно, это означает контекстили «это» функции - окно.если бы doSomeEffects был методом-прототипом, например this.doSomeEffects, скажем, для myObject, то myObject.doSomeEffects () приведет к тому, что this будет myObject.

6 голосов
/ 10 августа 2015

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

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

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

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

3 голосов
/ 10 марта 2012

Как объяснил Кайл, вы можете использовать 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

...