窗口上的 Javascript getter/setter

sim*_*ack 5 javascript

为什么下面的代码在 firefox 21.0 中会抛出 TypeError?

Object.defineProperty(window,'windowProperty',{
    get: function(){
        return 'windowProperty'
    },

    set: function(val){
        console.log('windowProperty is being set');
    },

    configurable: true,
});

var windowProperty;
Run Code Online (Sandbox Code Playgroud)

但是不使用 var 声明 windowProperty 是有效的:

windowProperty;
Run Code Online (Sandbox Code Playgroud)

或者

window.windowProperty;
Run Code Online (Sandbox Code Playgroud)

这种行为也存在于蜘蛛猴中:

var a=1;

Object.defineProperty(this,'a',{
    get: function(){
        return 'a';
    },
});
Run Code Online (Sandbox Code Playgroud)

Bal*_*alo 2

只写

windowProperty;
Run Code Online (Sandbox Code Playgroud)

不声明变量。它只是尝试返回最近上下文中的变量内容或者undefined如果找不到它。就像没有目标的任务一样。例如,您还可以编写随机文本而不会引发错误:

'Hello, world !';
123456;
undefined;
Run Code Online (Sandbox Code Playgroud)

使用 var 尝试重新定义之前已在代码中定义的属性,因此会出现错误。

编辑
正如 simonzack 所指出的,浏览器在重新定义变量时并不总是发送错误。例如:

var test; var test;
Run Code Online (Sandbox Code Playgroud)

不会抛出这个错误(即使这是一个坏主意并且一些 JS 验证器会警告你)。然而,通过定义 getter 和 setter,浏览器会“锁定”该属性(以防止冲突,例如,同一属性上有两个不同的 setter)。我的错,这是一个误解。

您想重新定义变量有什么原因吗?

编辑2
考虑到声明var在 之前defineProperty,它可以增加我的解释的准确性。事实上,当您第一次使用该var声明时,浏览器将其configurable状态设置为 false,这会阻止对其描述符进行更改(请参阅链接)。因此,当您尝试使用该defineProperty函数更改它时,会导致错误。一个看得更清楚的例子是将代码包装在闭包函数中。这样定义的windowPropertyvar就不一样了,一切就ok了。

(function () {
    var windowProperty;
    Object.defineProperty(...);
    //It works because the previously defined variable is in the scope of the function and thus is not the same as window.windowProperty.
})();
Run Code Online (Sandbox Code Playgroud)