2015-12-15 1 views
2

Я шел на что-то странное, делая сегодня код JS.Оператор области и OR в Javascript

Я хотел выполнить метод объекта, если это свойство существует, и какую-то другую функцию, если это не так. чувство немного фантазии, я написал что-то вроде:

var obj = { 
    method: function(){ 
     console.log(this); 
    } 
} 

(obj.method || some_other_function)(); 

Это выполняющей obj.method, если она существует, и some_other_function иначе.

Но this ключевое слово относится к window объекта, когда obj.method выполняется, и я абсолютно не знаю, почему.
Обратите внимание, что выполнение (obj.method)(); дает ожидаемый результат (это в виду мой объект)

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

Я не мог найти ответа ни здесь, ни в другом месте, ближайшая вещь, которую я нашел, это this interesting post, но она не охватывает этот конкретный случай.

Кто-нибудь знает, что там происходит?

вот fiddle, показывающий предмет в действии!

+0

Я бы порекомендовал прочитать это (длинно-ное, но хорошо объясненное): https://github.com/getify/You-Dont-Know-JS/blob/master/this%20&%20object%20prototypes/ch2.md –

+0

Спасибо за ссылку! Я стараюсь читать вещи, смотреть вещи, и я как бы нахожу свой путь, когда я кодирую, но у JS определенно есть некоторые особенности! Эта статья кажется очень подробной, спасибо снова! – mikake

ответ

4

(obj.method || some_other_function)(); является, по существу, такой же, как:

var f = obj.method || some_other_function; 
f(); 

Вы взяли функцию от контекста obj, запустив его через или, прежде чем вы это называете.

+0

Вы также должны объяснить, почему '(obj.method)();' не то же самое, что 'var f = obj.method; f(); ';) – plalx

+0

Возможно, я неправильно понял ключевое слово« this »... Я никогда не играл с контекстом выполнения до сих пор, и это может объяснить некоторые странные другие ошибки, с которыми я столкнулся в JS o_O Спасибо за это ясное и краткое объяснение! (это был своего рода нубийский первый вопрос на SO :) – mikake

+0

@plalx Я предполагаю, что круглые скобки без какого-либо оператора не изменяют содержащееся выражение, и, следовательно, не существует неявной промежуточной переменной? Я признаю, что вначале я не понял этого (именно поэтому я написал '(obj.method)();' как сравнение :) – mikake

0

obj.method() является синтаксическим сахаром для

method.call(obj) 

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

(obj.method || some_other_function)() 

делает его значение по функции и приведенное выше выражение синтаксический сахар для

(obj.method || some_other_function).call(this) 

this тогда текущий контекст, а не obj.

(obj.method)() еще вызов метода, так как (expression) и expression обрабатывают равным

+0

Спасибо, действительно, я не заметил, что мой '||' был создавая неявную переменную. И я также не понимал, что вы можете превратить метод в функцию (я почти только использую область, чтобы изолировать материал, не более того), и эта проблема мне очень помогла! – mikake

+0

Awesome edit, я только начинаю играть со всеми этими свойствами 'call',' bind', 'apply' ..., и теперь я прекрасно понимаю' call'! Теперь я четко знаю, почему ** это «ключевое слово» отличается. Это вечная проблема языков высокого уровня, вам нужно узнать все, что происходит под капотом, как аналог того, чтобы не изобретать все ...! – mikake

0

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

Однако выражение (obj.method || some_other_function)() не вызывается каким-либо объектом, оно просто ... вызывается, правильно? На самом деле происходит то, что это выражение вызывается из глобального пространства, которое в браузере является объектом window. Таким образом, вы можете думать о своем коде, как выполняется так:

obj : { 
    method: function(){ 
     console.log(this); 
    } 
} 

window.(obj.method || some_other_function)(); 

Оба some_other_function и obj.method вызываются из глобального пространства, поскольку они оцениваются как выражение внутри вашего || условный блок. Это выражение фактически является свойством объекта window, и это то, что его вызывает. Я был смущен об этом тоже поначалу, очень интересная проблема и благодаря Квентину за правильный ответ.

Вот отличный блог, который помогает прояснить this в JavaScript: http://javascriptissexy.com/understand-javascripts-this-with-clarity-and-master-it/

Отредактировано: Я обновил этот пост, чтобы отразить правильный ответ, мой первоначальный ответ был неверным.

+0

Спасибо за ваш ответ, @Travis, но проблема была в действительности только в отношении 'obj.method', в котором' this' ссылался на объект 'window'. Как отметил @Quentin, это связано с тем, что мой логический оператор OR принимает «метод» из «obj» (см. Его ответ), поэтому ключевым словом 'this' является окно. – mikake

+0

И это показывает, что даже люди (я), которые думают, что у них хорошее понимание «этого», все еще запутываются :) –

+0

Я тоже думал, что сделал, не волнуйся;) – mikake