2013-05-05 4 views
8

У меня есть этот простой код:Почему я теряю контекст этого в Javascript?

var o = { 
    a: 1, 
    b: 2, 
    f1: function() 
    { 
     alert(this.b); 
    } 
} 

var o2 = { 
    a: 11, 
    b: 22, 
    f2: function (j) 
    { 
     j(); 
    } 
} 

Но работает этот код:

o2.f2(o.f1) дающего неопределенной. (в то время как им ожидалось «22» в результате)

Теперь я знаю, что контекст куда-то ушел. и, следовательно, если изменить код в o2 на:

f2: function (j) 
    { 
     j.apply(this); 
    } 

Это делает работу, очевидно.

Но мой вопрос:

  • В какой стадии я потерять контекст?

Я не понимаю: когда j() работает, там являетсяb свойство в o2 объекта.

Что мне не хватает?

jsbin

+9

Когда вы называете это 'f()' - методы JavaScript - это * «несвязанные функции» * (то есть, в отличие от методов на других языках, они * не * связаны с конкретным объектом/экземпляром), и это вызов -site, который определяет 'this' при вызове. (Конечно, см. ['Function.bind'] (https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Function/bind) или эквивалентные эмуляции.) – user2246674

+0

Вы потеряете его как можно скорее когда вы проходите мимо 'o.f1'. Если вы выполняете 'var x = o.f1' и вызываете' x() ',' f1' больше не привязывается. – Blender

+0

@Blender Я знаю это. но почему «это» не относится к «o2»? это то, что я не понимаю. –

ответ

6

Я нашел, что у Крокфорда было отличное описание того, как это работает.Функции в JavaScript может быть использовано в 4 стилях:

  1. Функция «» стиль
  2. «Метод» стиль
  3. «Конструктор» стиль
  4. «Зов или применить» стиль.

Возможно, у меня точно указаны точные названия, но дух тот же. Вы должны обязательно получить книгу «JavaScript: хорошие части», если у вас ее нет.

Так или иначе - на ваш вопрос. Главное, что значение, если «это» зависит от того, какой стиль вы используете.

// function invocation style, 
var f = function() { console.debug(this); } 
f(); // "this" is bound to the global object. 

// "method" invocation style 
var obj = { 
    f: function() { console.debug(this); } 
}; 

obj.f(); // "this" is bound to "obj", the object on which the function was invoked 

// so important bit is : 

var f = obj.f; 
f(); // "this" is global object 
obj.f() // "this" is obj 

В вашем примере вы теряете «это» из-за того, что вы вызываете функцию.

1

Если вы делаете это, как следующим образом,

функция будет вызываться в контексте o2

var o2 = { 
    a: 11, 
    b: 22, 
    f2: function (j){ 
     this.temp = j; 
     this.temp(); 
    } 
}; 

также они будут работать также:

f2: function (j){ 
     j.apply(this); 
} 

f2: function (j){ 
     j.apply(o2); 
} 

В противном случае вы называете это просто lik e обычная функция вне контекста.

j Вырван из контекста, и вы не сделали никаких сложных закрытий на нем (это не ваше намерение), поэтому для создания «этой» работы в нем вам нужен объем. Эта область в вашем вопросе для j - это окно, в котором нет «b», поэтому вы получаете «неопределенный».

+0

приятный трюк .. + 1. –

+0

Да, использование «этого» является ответом – Cherniv

0

Проверить это тесты:

o.f1(); // alerts 2 

var f3 = o.f1; // (*) 

f3(); // alerts undefined 

o2.f2(f3); // alerts undefined 

f3.apply(o2); // alerts 22 

Я понимаю, что при передаче функции в качестве параметра контекст теряется точно так же, как он потерял в (*) указал в коде выше.

Что происходит j = arguments[0] = o.f1, и в этот момент вы теряете контекст.

При передаче функции в качестве параметра вы просто передаете ссылку в память этой функции. Без привязки контекста вы пропустите простой вызов j(). Вот почему вам нужно использовать apply или трюк this, показанный Ihsan.

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