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



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



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



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



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();
545   7  

7 ответов:

в JavaScript the

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();         
 }      

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

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

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" был прототипом метода, например, это.doSomeEffects На говорят строки "MyObject", затем мой_объект.doSomeEffects () приведет к тому, что "это" будет "myObject".

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

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

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

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

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

вы также можете сделать это .привязать() метод,

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() {

      // now 'this' pointer is referring to the std_obj when calling by bound function
      if (this.activeEffect=="fade") { }
          alert(this.activeEffect);
    }

    var newBoundFunction= doSomeEffects.bind(std_obj);
      newBoundFunction();   
  }
};

мы можем установить значение этого явно с помощью call(), bind () и apply (). Три очень похожи, но важно понимать незначительные различия.

и каждый тут же вызывается. Вызов принимает любое количество параметров: это, а затем дополнительные аргументы. Применить принимает только два параметра: это, а затем массив дополнительных аргументы.

ты все еще следишь за мной? Пример должен сделать это более ясным. Посмотрите на код ниже. Мы пытаемся сложить числа. Скопируйте это в консоль браузера и вызовите функцию.

function add(c, d) {
  console.log(this.a + this.b + c + d);
}
add(3,4);
// logs => NaN

функция add регистрирует NaN (не число). Это потому что это.и это.б неопределены. Они не существуют. И вы не можете добавить число к чему-то неопределенному.

давайте введем объект в уравнение. Мы можем использовать call() и применить () для вызова функция с нашим объектом:

function add(c, d) {
  console.log(this.a + this.b + c + d);
}
var ten = {a: 1, b: 2};
add.call(ten, 3, 4);
// logs => 10
add.apply(ten, [3,4]);
// logs => 10

когда мы используем добавить.вызов () первый параметр-это то, к чему это должно быть привязано. Последующие параметры передаются в вызываемую функцию. Таким образом , в add (), это.а относится к десяти.и это.b относится к десяти.B и мы получаем 1+2+3+4 вернулся, или 10.

добавить.применить() аналогично. Первый параметр - это то, к чему это должно быть привязано. Следующий параметр представляет собой массив аргументов, которые будут использоваться в функция.

как насчет привязки? Параметры в bind() идентичны call() но bind () вызывается не сразу. Вместо этого bind () возвращает функцию с контекстом этой привязки уже. Из-за этого bind() полезен, когда мы не знаем всех наших аргументов заранее. Опять же, пример должен помочь с вашим пониманием:

var small = {
  a: 1,
  go: function(b,c,d){
    console.log(this.a+b+c+d);
  }
}
var large = {
  a: 100
}

скопируйте в консоль. Тогда звоните

small.go(2,3,4);
// logs 1+2+3+4 => 10

прохладный. Ничего нового здесь нет. Но что, если мы хотим использовать ценность большой.вместо этого? Мы можем использовать вызов/применение:

small.go.call(large,2,3,4);
// logs 100+2+3+4 => 109

теперь, что если мы еще не знаем все 3 аргумента? Мы можем использовать персонализация:

var bindTest = small.go.bind(large,2);

если мы утешаем.запишите нашу переменную выше, bindTest, мы можем видеть, с чем мы работаем

console.log(bindTest);
// logs => function (b,c,d){console.log(this.a+b+c+d);}

помните, что с помощью bind возвращается функция, которая уже имеет эту привязку! Таким образом, наше это было успешно привязано к нашему большому объекту. Мы также уже передали наш второй аргумент как число 2. Позже, когда мы узнаем остальные аргументы, мы можем передать их в:

bindTest(3,4);
// logs 100+2+3+4 => 109

для ясности, вот весь код вместе в один блок. Просмотрите его и скопируйте в свою консоль, чтобы действительно понять, что происходит!

var small = {
  a: 1,
  go: function(b,c,d){
    console.log(this.a+b+c+d);
  }
}
var large = {
  a: 100
}
small.go(2,3,4);
// logs 1+2+3+4 => 10
var bindTest = small.go.bind(large,2);
console.log(bindTest);
// logs => function (b,c,d){console.log(this.a+b+c+d);}
bindTest(3,4);
// logs 100+2+3+4 => 109

запомните несколько вещей:

значение этого обычно определяется контекстом выполнения функций.

в глобальной области видимости, this ссылается на глобальный объект (объект window).

когда используется новое ключевое слово (конструктор), которое привязывается к создаваемому новому объекту.

мы можем установить значение этого явно с помощью call(), bind () и apply ().

функции стрелки не связывают это-вместо этого это связано лексически (т. е. на основе исходного контекста)

Comments

    Ничего не найдено.