2014-06-28 5 views
0

Я думал, что знаю JavaScript, похоже, я этого не делаю.Использование `this` с объектными литералами

Я хочу определить такой объект. (Пример из http://www.phpied.com/3-ways-to-define-a-javascript-class/)

var apple = { 
    type: "macintosh", 
    color: "red", 
    getInfo: function() { 
     return this.color + ' ' + this.type + ' apple'; 
    } 
} 

Ну, это выглядит хорошо, давайте печатать информацию ...

apple.getInfo() //returns "red macintosh apple" as expected 

Хорошо, теперь взять функцию, и запустить его снова ...

var func = apple.getInfo; func(); //returns "undefined undefined apple" 

Ну, это не то, что я ожидал. По-видимому, this интерпретируется как window. Это не то, что я хотел.

Мой вопрос: что такое идиоматический, предпочтительный способ перезаписи литерала apple, так что apple.getInfo возвращает функцию, которая может запускаться отдельно, но все еще использовала свойства объекта?

+0

Также см. Http://stackoverflow.com/questions/20279484/how-to-access-the-correct-this-context-inside-a-callback –

ответ

6

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

Выполнение apple.getInfo() делает this относится к apple. Но называть его func() - это как бы вызов window.func() (при условии, что он находится в глобальном пространстве), что делает this ссылкой на window.

Если вы хотите «направить» значение this на функцию, выполните bind. Он создает копию функции с this, принудительно переданной первым параметром.

var func = apple.getInfo.bind(apple); 
// all calls to `func` will have `this` "forced" as `apple` 

Если вы хотите, чтобы диктовать this на вызов, но не постоянно искажать this на func (например, как bind делает это), вы можете пойти с call или apply:

var func = apple.getInfo; 
func.call(apple); 
func.apply(apple); 
// Both function will have `this` as `apple` only for the call. 
+0

Хм, интересно! Я не знал, что это такой комплекс. Мне нужна была функция для вызова в качестве обратного вызова, я думал, что могу просто использовать 'apple.getInfo', а не создавать анонимные функции.Хорошо, тогда я просто сделаю еще одну анонимную функцию. Спасибо! –

+0

Приложение: На самом деле я фактически использовал .bind вместо анонимной функции, потому что он просто «кажется» более чистым. (Не уверен, что это быстрее/эффективнее или нет.) –

+0

Да, я был неправ! Закрытие * действительно * более эффективно, чем привязка, во всех браузерах. http://jsperf.com/bind-vs-self-closure/7 –

1

@ Джозеф мечтателя дал отличный ответ.

Поскольку OP ищет способ иметь apple.getInfo, всегда возвращайте функцию, которая не имеет проблемы undefined, я решил, что я выбрал эту альтернативу.

var apple = { 
    type: "macintosh", 
    color: "red" 
}; 

apple.getInfo = (function() { 
    return this.color + ' ' + this.type + ' apple'; 
}).bind(apple); 

Таким образом, вы не должны вызывать apple.getInfo.bind(apple) каждый раз, когда вы хотите создать новую ссылку на эту функцию.

Обратите внимание, что вы не можете поставить getInfo в исходный объект буквальным, так как в тот момент, apple не имеет значение, присвоенное ему и .bind(apple) не будет работать должным образом.

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