Как оказалось, это один из темных углов спецификации ECMA для ECMAScript (отсюда и JavaScript):
Наконец, значение назначено для использования с ключевым словом this. Если присвоенное значение относится к объекту, то средства доступа к свойствам с префиксом this ссылаются на свойства этого ключевого слова. Если назначенное (внутренне) значение равно нулю, ключевое слово this будет ссылаться на глобальный объект.
(http://jibbering.com/faq/notes/closures/; спасибо @ Brian Flanagan за ссылку)
Очевидно, что во время выполнения функции, которая назначена переменной (внутри другого Function
), контекст теряется, таким образом, область видимости устанавливается равной нулю, и this
будет ссылаться на Window
Object
.
Я не совсем уверен, стоит ли ожидать чего-то от Function
, инициализированного как локальная переменная. Обычно я ожидаю, что у замыкания будет доступ к области, в которой оно было создано, пока оно находится в памяти, включая его предшественника в цепочке областей.
Это поведение отличается от функции, которая является свойством Function
Object
, где контекст не потерян и this
будет правильно указывать на владельца элемента Function
(который является Function
Object
или членом в зависимости от количества слоев).
Решением этой проблемы (при сохранении частных Function
членов, то есть членов, которые доступны только из области действия Function
) является обертывание функции внутри другого Function
с использованием Function.prototype.apply
(или * 1035) *) чтобы установить контекст вручную:
function F() {
this.field = "value" ;
var self = this ;
var init = function(value) {
(function() {
this.field = value ;
}).apply(self,value) ;
} ;
this.method = function() {
return this.field ;
} ;
init( arguments[0] ) ;
}
Это аналогично Function.prototype.bind
, представленному в JavaScript 1.85, а также библиотеке PrototypeJS.
Редактировать: Забыл скобки вокруг вложенной функции в init
. Это приведет к SyntaxError
.