2015-05-01 6 views
1

Теперь это новый для меня. Я искал вокруг, но не могу найти решение в другом месте.'this' возвращает либо 'Object', либо 'Window' внутри того же объекта

У меня есть этот код (CoffeeScript):

PositionDetector = -> 

    detectPosition : -> 
     console.log this # outputs 'Object' (OK) 
     navigator.geolocation.getCurrentPosition(this.locationHandler) 

    locationHandler : (position) -> 
     console.log this # outputs 'Window' (WHY??) 

positionDetector = new PositionDetector() 
positionDetector.detectPosition() 

(или соответствующий скомпилированный JavaScript, если вы предпочитаете):

var PositionDetector = function() { 

     detectPosition : function() { 
     console.log(this); // outputs 'Object' 
     navigator.geolocation.getCurrentPosition(this.locationHandler); 
     }, 

     locationHandler : function(position) { 
     console.log(this); // outputs 'Window' 
     } 
} 

var positionDetector = new PositionDetector(); 
positionDetector.detectPosition(); 

Вопрос, почему же первый 'это' вывод «Объект», а второй - «Окно»?

Live demo in a Codepen

+0

@vinayakj: Если вы имеете в виду код справа вверху, потому что это не JavaScript, это CoffeeScript. Джереми опубликовал перевод JavaScript во втором блоке. –

ответ

4

Вопрос, почему же первый 'это' выход 'Object' и второй один 'Window'?

this устанавливается прежде всего, как функция называется (на данный момент *), не там, где она определена. В первом случае способ, которым вы вызываете функцию, - это ссылка на объект (positionDetector.detectPosition()), поэтому механизм JavaScript устанавливает this как объект, который вы использовали как часть выражения, вызывающего вызов. Во втором случае функция не вызывается как часть выражения, возвращающего ссылку на функцию из свойства объекта, поэтому this принимает значение по умолчанию (глобальный объект в свободном режиме, undefined в строгом режиме). Вот простой пример:

var obj = { 
    foo: function() { 
     console.log(this); 
    } 
}; 
var f = obj.foo; 
obj.foo(); // `this` is `obj` during the call 
f();  // `this` is not `obj` during the call 

Чтобы решить эту проблему, можно использовать Function#bind использовать определенную this значение во время обратного вызова:

navigator.geolocation.getCurrentPosition(this.locationHandler.bind(this)) 

Function#bind создает функцию, которая при вызове будет вызывать оригинал файл со значением this (и любыми необязательными аргументами, которые вы предоставляете).

Подробнее о this(в моем блоге):


* "сейчас": ES6 вводит CoffeeScript стиле функции стрелка , которые имеют this значение, заданное контекстом, в котором создается функция. Это не помогло бы вам здесь, но это делает мой обычный «... задан в первую очередь тем, как функция вызывается ...» * утверждение больше не верно. :-)

+0

Замечательный и быстрый двойной ответ, благодаря вам обоим. Я не могу проверить оба ответа, хотя, но я могу +1 :) –

+0

Также писать закрытие может исправить ситуацию. Только мои пятьдесят центов. – Ihsan

3

Потому что this зависит от вызывающего абонента. Вызывающий абонент this.locationHandler - navigator.geolocation.getCurrentPosition(callback), и он вызывает функцию, как callback(), обратите внимание, что в этом вызове нет точки, то есть нет значения для this.Решение состоит в том, чтобы установить this постоянно используя bind:

navigator.geolocation.getCurrentPosition(this.locationHandler.bind(this)) 

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

+0

Замечательный и быстрый двойной ответ, благодаря вам обоим. Я не могу проверить оба ответа, но я могу +1 :) –

0

Оба T.J. Crowder & elclanrs являются правильными.

В качестве краткого объяснения: «это» относится к объекту контекст (AKA области видимости), и это не работает точно так, как вы ожидали в JavaScript, к сожалению,

  • detectPosition() вызывается в контексте PositionDetector тобой.
  • locationHandler() вызывается в контексте окна, которое является глобальным объектом и создателем события.

ИМХО Эта ситуация делает Javascript глупым. Существует два способа преодоления этого эффекта. Во-первых, это метод «привязки», как они показали. Второй - магическое поколение «закрытия».

+0

Я никогда не сталкивался с этой ситуацией в объекте со многими методами, может быть, потому, что я вызывал методы извне, а не из друг друга. Но я не вещь javascript глупа :) Это темпераментно, но вот почему мне это нравится! Спасибо за ваш вклад. –

+0

Ну почему -1? Уважаемые? – Ihsan

+1

Не знаю. Другой тихий downvoter, как обычно. Я сделал +1 для баланса ... –

Смежные вопросы