2012-05-09 5 views
5

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

Я упал на пятки в любви с JavaScript. Pure JS, то есть не jQuery, prototype.js, dojo ... Так что, естественно, я взял использование закрытий. В некоторых случаях, однако, this улавливает меня здесь. Возьмите этот фрагмент кода для одного:

function anyFunc(par) 
{ 
    //console.log(par); 
    console.log(this); 
} 

function makeClosure(func) 
{ 
    return function(par) 
    { 
     return func(par); 
    } 
} 
var close = makeClosure(anyFunc); 
close('Foo'); 

var objWithClosure = {cls:makeClosure(anyFunc),prop:'foobar'}; 
objWithClosure.cls(objWithClosure.prop); 

var scndObj = {prop:'Foobar2'}; 
scndObj.cls = makeClosure; 
scndObj.cls = scndObj.cls(anyFunc); 
scndObj.cls(scndObj.prop); 

Во всех трех случаях, this журналы как объект окна. Это легко исправить, конечно:

function makeClosure(func) 
{ 
    return function(par) 
    { 
     return func.call(this,par); 
    } 
} 

Это исправление работает, я положил его здесь, чтобы избегать людей, отвечая на это, не объясняя, что мне нужно знать: почему это ведет так, как это делает здесь?

гарантирует, что вызывающий объект фактически является объектом, к которому принадлежит закрытие. Что я не понимаю, так это: Конечно, this указывает на объект окна в первом случае, но в других случаях он не должен. Я попробовал logging this в функции makeClosure перед возвратом, и он сам зарегистрировал сам объект, а не объект window. Но когда используется фактическое закрытие, this возвращается к объекту окна. Зачем?

Единственное, что я могу придумать, это то, что, передавая функцию anyFunc в качестве аргумента, я фактически прохожу window.anyFunc. Так что я попытался это быстро исправить:

function makeClosure(func) 
{ 
    var theFunc = func; 
    return function(par) 
    { 
     theFunc(par); 
    } 
} 

с ожидаемыми результатами, this теперь указывает на объекты, но опять-таки: почему? У меня есть несколько идей (theFunc - ссылка на функцию в локальной области [this > private: theFunc]?), Но я уверен, что здесь есть люди с гораздо большим количеством ноу-хау, когда дело доходит до JS, поэтому я надеялся получить больше объяснений или ссылки на статьи стоит читать из них ...

Благодарности

Update

Here's a fiddle, может быть, я оставил что-то, но здесь это регистрирует все виды вещей;)

E dit/Обновление 2

The case that confuses me есть здесь.

Final Редактировать

Хорошо, Это становится довольно грязный пост. Таким образом, чтобы уточнить: То, что я ожидал, было поведение похоже на это:

function makeClosure() 
{ 
    function fromThisFunc() 
    { 
     console.log(this); 
    } 
    return fromThisFunc; 
} 

var windowContext = makeClosure(); 
windowContext(); 
var objectContext = {cls:makeClosure()}; 
objectContext.cls(); 

Что привлекло меня, было то, что функция anyFunc не была объявлена ​​в правильном объеме, и, следовательно, this указал на объект окна. Я нашел это, прочитав ancient scroll, который я нашел где-то в Интернете.

Но кое-что посложнее произошел потому, что объект функции теперь именуется по globalVar был создан с [[Scope]] собственность ссылки на цепочку областей видимости, содержащую Activation/Variable объект, принадлежащий к контексту выполнения в который был создан (и глобальный объект). Теперь объект Activation/Variable не может быть собран в виде мусора, так как выполнение объекта функции, на которое ссылается globalVar, необходимо будет добавить целую цепочку цепочки из своего свойства [[scope]] в область контекста выполнения, созданного для каждого вызова Это.

Так что мне нужно было сделать, было Упростить, а затем усложнять:

function fromThisFunc() 
{ 
    console.log(this); 
} 

function makeClosure(funcRef) 
{ 
    //some code here 
    return funcRef; 
} 

Это должно работать, не так ли?

PS: Я за исключением ответа Алнитак, но особая благодарность Феликс Клинг за все терпение и информацию.

+0

Я не получить то, что другой ответ, чем ссылка на глобальное объяснение закрытия может сделайте. Этот курс является отличным чтением и должен устранить все неопределенности: http://ejohn.org/apps/learn/ –

+0

Проблема не в том, что я не закрываю. То, что вызывает головные боли, заключается в том, что я не совсем уверен, что происходит с этим объектом, когда делает замыкания так, как я здесь. –

+2

Я не могу воспроизвести описанную вами ситуацию. Я получаю 'DOMWindow',' Object', 'Object': http://jsfiddle.net/GErkX/, тогда как ваше второе« исправление »дает мне 3 x' DOMWindow': http://jsfiddle.net/tZXQF/ –

ответ

4

Как только вы звоните:

return func(par); 

Вы создаете новую область (с его собственными this) и в этом случае, потому что вы не указали объект, this === window обычно или неопределенных в строгий режим. Вызываемая функция не наследует то, что this было в области вызова.

Пути, чтобы установить значение для этого являются:

myobj.func(par); // this === myobj 

или

func.call(myobj, ...) // this === myobj 

Есть также:

+1

или -apparently- создать локальный var в функции 'makeClosure' и назначить параметр func этой переменной ... также,' return func (par) 'является телом функции, функции, возвращаемой объекту , поэтому я предположил, что вызов функции func (par) 'будет сделан в контексте объекта. Почему не так? –

+0

@EliasVanOotegem Я все еще пытаюсь разобраться в этом первом случае ... Я не могу воспроизвести его локально. – Alnitak

+2

@EliasVanOotegem: Я думаю, что ваши тесты некорректны, особенно последний. Всякий раз, когда вы выполняете просто функцию вызова 'foo()', 'this' будет ссылаться на глобальный объект, независимо от того, где была определена функция. В какой среде вы тестируете код? Создание локальной переменной не имеет значения в этом случае. Параметр также локальный. Ваше первое исправление работает отлично: http://jsfiddle.net/GErkX/ –

1

Значение this зависит только позвонить ли функции в качестве метода или функции ,

Если вы вызываете его как метод, this будет объектом, что метод принадлежит:

obj.myFunction(); 

Если вы называете это как функция, this будет window объект:

myFunction(); 

Обратите внимание, что даже если вы находитесь в методе, принадлежащем объекту, вам все равно придется вызывать другие методы в объекте с использованием синтаксиса метода, иначе они будут называться функциями:

this.myOtherFunction(); 

Если поместить ссылки на метод в переменной, вы отделить его от объекта, и он будет называться как функция:

var f = obj.myFunction; 
f(); 

В call и apply методы используются называть функция как метод, даже если это не метод в объекте (или, если это метод в другом объекте):

myFunction.call(obj); 
+0

спасибо, но на самом деле не ответ на этот вопрос ... В настоящее время я использую 'call', но я хочу знать _why_ JS ведет себя так, как это делает. на бите ссылки метода: довольно странно, что когда я создаю ссылку на функцию (не метод, функцию) в функции, которая привязана к объекту, эта функция ref будет вызвана как метод –

+0

+1 для отсоединить метод tip, btw –

+0

@EliasVanOotegem это потому что, как только вы _attach_ эта функция ссылается на объект, он становится методом этого объекта. Это противоположность тому, что происходит, когда вы _detach_ метод. – Alnitak

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