在Object.defineProperty中使用自执行函数的构造函数中使用“this”构造新对象后的未定义属性

时间:2014-05-29 15:50:45

标签: javascript ecmascript-5

我尝试使用类似TypeScript的结构来模拟自动执行函数中的枚举值:'属性。我查看了构造函数中使用ECMAScript5 / Crockford Object.defineProperty()的例子(使用' this'),但找不到多少。据我所知,自执行函数应该用两个属性填充两个对象,并且闭包是正确的('这个'不是窗口对象)。这是我的设计模式:

var player = {};
var Foo = function () {
    this.levelIndex;
    Object.defineProperty(this, 'levelIndex', {
        value: (function (levelIndex) {
            levelIndex[levelIndex.ONE =   0] = 'ONE';
            levelIndex[levelIndex.TWO =   1] = 'TWO';
            levelIndex[levelIndex.THREE = 2] = 'THREE';
            levelIndex[levelIndex.FOUR =  3] = 'FOUR';
            levelIndex[levelIndex.FIVE =  4] = 'FIVE';
            // setup the player object with the properties of the levelIndex
            // before it becomes non-enumerable:
            for (var i in levelIndex) {
                Object.defineProperty(player, i, {
                  value: isNaN(levelIndex[i]) ? 'LEVEL_' + levelIndex[i] : levelIndex[i],
                  enumerable: false
                });
                alert(player[i]); //<-- LEVEL_ONE, LEVEL_TWO, LEVEL_THREE, LEVEL_FOUR, LEVEL_FIVE, 0, 1, 2, 3, 4
            }
            alert('window? : ' + this === window); //<-- false
        })(this.levelIndex || (this.levelIndex = {})),
        writable: false,
        enumerable: false,
        configurable: false
    });
};
var foo = new Foo();
alert(player.ONE); //<-- 0
alert(foo.levelIndex); //<-- undefined
alert(foo.levelIndex.ONE); //<-- Uncaught TypeError: Cannot read property 'ONE' of undefined 

为什么foo.levelIndex在这里未定义?

编辑:修正了return levelIndex;添加到匿名函数调用。

欢迎对我的设计模式或改进建议发表任何评论!

2 个答案:

答案 0 :(得分:2)

您使用普通函数调用调用匿名函数,因此this的值在严格模式下为undefined,否则为全局对象(window)。肯定不会的是对你所定义的对象文字的引用。

“Foo”功能的第一行看起来有点可疑:

    this.levelIndex;

这对任何事都没有影响;特别是,它不会导致在this引用的对象上创建名为“levelIndex”的属性。

编辑 - 另外,当我更多地了解您正在做什么时,很明显为什么“levelIndex”属性最终为undefined:该对象文字具有“值”设置为匿名函数调用的返回值的属性。但是,匿名函数没有return语句,因此对Object.defineProperty的调用涉及一个属性对象,其“value”属性设置为undefined。如果你添加

    return levelIndex;

到该匿名函数的末尾,它(可能)起作用。 (我想会的。)

答案 1 :(得分:0)

基于@Pointy和@Bergi的帮助,这是更新的工作代码:

http://jsfiddle.net/5j9W5/

var player = {};
var Foo = function () {
    Object.defineProperty(this, 'levelIndex', {
        value: (function (levelIndex) {
            levelIndex[levelIndex.ONE = 0] = 'ONE';
            levelIndex[levelIndex.TWO = 1] = 'TWO';
            levelIndex[levelIndex.THREE = 2] = 'THREE';
            levelIndex[levelIndex.FOUR = 3] = 'FOUR';
            levelIndex[levelIndex.FIVE = 4] = 'FIVE';
            return levelIndex;
        })(this.levelIndex || (this.levelIndex = {})),
        writable: false,
        enumerable: false,
        configurable: false
    });
    // setup the player object with the properties of the levelIndex:
    for (var i in this.levelIndex) {
        Object.defineProperty(player, i, {
            value: isNaN(this.levelIndex[i]) ? 'LEVEL_' + this.levelIndex[i] : this.levelIndex[i],
            enumerable: false
        });
    }
};
var foo = new Foo();
alert(player[0]); //<-- LEVEL_ONE
alert(foo.levelIndex.FIVE); //<-- 4
for (var i in player) {
    alert(i + ' ' + player[i]); //<-- no output (properties are not enumerable here)
}