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();
7 ответов:
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();
вы также можете сделать это .привязать() метод,
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