2013-06-12 1 views
5

Я читал некоторые documentation about javascript и наткнулся на следующем примере:Почему вложенная локальная функция связывает `this` к окну вместо родителя

var o = { 
    value: 1, 
    outer: function() { 
    var inner = function() { 
     console.log(this); //bound to global object 
    }; 
    inner(); 
    } 
}; 
o.outer(); 

Он выводит window.

Я не могу понять, почему является this ключевое слово связано с глобальным объектом (window) вместо родительского объекта (outer).
Если вы хотите получить доступ к outer из inner «сферы s, вы должны пройти outer» s this (который так же, как проходит outer сам) в своей локальной inner функции в качестве аргумента. Таким образом, как ожидалось:

var o = { 
    value: 1, 
    outer: function() { 
    var inner = function (that) { 
     console.log(that); //bound to global object 
    }; 
    inner(this); 
    } 
}; 
o.outer(); 

выходы outer.

Разве это немного нонсенс, что в outer «s объем this связан с самим объектом (т.е. outer), в то время как в inner» s сферы, которая является локальной для outer, this является повторно оценка к глобальному объекту (т.е. он переопределяет привязку outer)?


В ECMAScript specs говорится, что при входе в контекст выполнения кода функции, если «вызывающий при условии thisArg» либо нуля или неопределенных, то this связан с глобальным объектом.

Но следующее:

var o = { 
    outer: function() { 
     var inner = function() { 
      console.log('caller is ' + arguments.callee.caller); 
     }; 
     inner(); 
    } 
} 

выводит объект outer сам:

caller is function() { 
    var inner = function() { 
     console.log('caller is ' + arguments.callee.caller); 
    }; 
    inner(); 
} 



На стороне, но, вероятно, уместно, примечание:
В строгий режим первый вывод фрагмента кода undefined вместо окна.

+3

Это потому, что, как вы вызываете 'внутренний '-' inner(); '. Значение 'this' устанавливается так, как вы вызываете функцию. Любое anyways, 'inner' не имеет никакого отношения к' external', это всего лишь локальная переменная. Если вы использовали 'console.log (this);' внутри 'outer' и называли его следующим:' var a = o.outer; a(); ', вы получите' окно'. Вы можете подумать, что это вздор, но он разработан именно так - вам нужно научиться правильно его использовать. – Ian

+0

«Спецификации ECMAScript заявляют, что при вводе контекста выполнения для кода функции, если« вызывающий объект, предоставленный thisArg », является либо нулевым, либо неопределенным, то он привязан к глобальному объекту». - Ты не ответил на свой вопрос? 'inner()' не указывает thisArg. –

+0

@ Значит, область, в которой вызов сделан, вообще не имеет значения? –

ответ

3

Это как раз то, как язык работает.

Каждую Время вызывается функцией, this будет сброшен. Во вложенной (внутренней) функции он не наследует значение из охватывающей области, как другие (явно объявленные) переменные.

По умолчаниюthis будет установлен в window, если функция не вызывается как:

  • myObj.func(arg1, ...) или
  • func.call(myObj, arg1, ...) или
  • func.apply(myObj, [arg1, ...])

в этом случае this будет равен myObj

функции, называемый любым другим способом, даже если он был первоначально определен как свойство объекта (т.е. var func = myObj.func; func() будет использовать window.

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

var myFunc = myObj.func;    // obtain reference to func 
var bound = myFunc.bind(someOtherObj); // bind it to "someOtherObj" 

bound();        // this === someOtherObj 
bound.call(myObj)      // this still === someOtherObj 
6

Это потому, что this устанавливается, когда функция работает, а не когда она определена.

Например:

var o = { 
    func: function(){ 
     console.log(this); 
    } 
}; 

Когда вы звоните o.func(), вы делаете это в контексте o, поэтому он работает, как ожидалось.

Теперь предположим, что вы делаете это:

var f = o.func; 
f(); 

Это не будет работать, как ожидалось. Это связано с тем, что когда вы звоните f(), у него нет никакого контекста, связанного с ним, поэтому this будет window.

Вы можете исправить это, используя .call, чтобы изменить значение this.

var f = o.func; 
f.call(o); // sets `this` to `o` when calling it 
Смежные вопросы