Javascript:使用对象字面量时,属性的顺序是否重要?

3
从以下示例中获取: http://www.phpied.com/3-ways-to-define-a-javascript-class/ 这篇文章介绍了三种定义JavaScript类的方式。
var apple = {
    type: "macintosh",
    color: "red",
    getInfo: function () {
        return this.color + ' ' + this.type + ' apple';
    }
};

现在我正在将getInfo()方法移动到对象声明的顶部。
var apple = {
    getInfo: function () {
        return this.color + ' ' + this.type + ' apple';
    },
    type: "macintosh",
    color: "red",
};

apple.getInfo();
red macintosh apple

我原本期望JavaScript解析器/编译器会失败,因为this.color和this.type尚未定义。这是如何在内部工作的?(此问题最初是一个ExtJS框架问题,链接在这里:ExtJS:通过原型上的函数设置属性:这是一种安全模式吗?,但我意识到这是一个更普遍的JavaScript问题,因此提出了这个新问题)

一旦您调用 apple.getInfo();,整个 apple 对象已经被定义。 - bumpy
好问题,问得好。 - T.J. Crowder
解析器不会失败,即使您向此函数添加了永远不会被定义的属性。这与JavaScript是鸭子类型[https://en.wikipedia.org/wiki/Duck_typing]有关。 - Sam
正如 @hege_hegedus 所说的那样,在第8行的 } 后面应该有一个分号。 - Sam
3个回答

2

该函数在实例化后被调用。定义时不会运行,也不会尝试访问属性,但在调用 getInfo() 函数的位置,它们都是存在的。实际上,在解释器解析各个属性之间,没有任何运行自定义 JavaScript 代码的方法。


2

只有在调用函数时,函数内部的代码才会被执行,因此直到调用 apple.getInfo() 时,this 的属性 color 才会被评估。

编辑:

var apple = {
    getInfo: function () {
        return this.color + ' ' + this.type + ' apple';
    },
    type: "macintosh",
    color: "red",
    }
}

此时,苹果对象已被定义,而getInfo属性是一个函数,在评估时将返回属性。
apple.getInfo();

该函数现在已被评估,属性colortype此时已经被定义。

当函数被评估时,它获取这些属性的值,因此如果更改属性colortype,则函数的返回值也会随之改变。


1
此时,苹果对象已被定义,getInfo属性是一个函数,当它被评估时将返回属性。 - Manu

1
我原本以为JavaScript解析器/编译器会失败,因为this.color和this.type尚未定义。 但是编译器的解析器并不在意。JavaScript不会在代码使用前评估属性或变量是否存在。对于属性,不存在的属性会被创建(如果您正在写入它),或者导致值为undefined(如果您正在从中读取),所以即使您的对象没有color和type属性,该代码仍不会抛出错误。您只会得到字符串“undefined undefined apple”。 JavaScript:使用对象字面量时,属性的顺序是否重要?

重要吗? 可能不重要。 有意义吗? 是的,从 ES6(又称 ECMAScript 6 或 ECMAScript 2015)开始,最新规范中对象初始化器中属性的顺序决定了它们被创建的顺序,进而部分设置了它们在 for-in 循环中被访问的顺序,它们在 Object.keys 数组中出现的顺序等(部分是因为可以转换为整数的属性名会被处理得不同)。但你很少关心这些细节。详情请参见 this answerthis answer(后者主要涉及数组,但也涉及非数组对象)。


which in turn sets the order in which they're visited by for-in loops” 的意思是“这决定了它们被 for-in 循环访问的顺序”。您确定吗?我在 http://ecma-international.org/ecma-262/6.0/index.html#sec-for-in-and-for-of-statements 上没有看到这个说法,而且 http://ecma-international.org/ecma-262/6.0/index.html#sec-object.keys 中说:“如果实现定义了 for-in 语句的特定枚举顺序……”(我加了重点)。这个“如果”很重要。虽然有很多关于“按列表顺序”的引用,但没有任何东西可以定义对象属性的列表顺序(除了明显的源代码顺序)。 - RobG
有点混乱。Enumerate方法内部说:“枚举属性的机制和顺序没有指定,但必须符合下面指定的规则”,然后OwnPropertyKeys说:“…按属性创建的顺序…”。我猜我已经自言自语了。或者是被说服了。无论怎样。 - RobG
@RobG: 是的,我确定。有很多引擎在这样做(但在索引样式属性与非索引样式属性方面略有不同),所以他们决定规定它。我会看看是否可以找到我的答案,在规范中砍出一条路来看看它是否真的是正确的。 :-) - T.J. Crowder
@RobG:在答案中添加了链接,这些链接是其他答案,其中我记录了我通过规范进行的黑客攻击。 - T.J. Crowder
谢谢,但还是有些混乱。在符合ECMAScript 2015标准的实现中,数字键总是排在最前面,并按数字顺序排列,而不管它们何时添加。我仍然不理解Object.keys的“if”语句。也许如果数组和对象完全分开成为两个对象,那么问题就可以解决了,但属性枚举规则似乎试图同时适用于两者,却并没有真正适用于任何一个。 - RobG
@RobG:现在的情况比以前好多了,因为人们过去总是依赖顺序,尽管这是不可靠的。:-) 至于 Object.keys 中的 "if",你是指“如果实现定义了 for-in 语句的特定枚举顺序,则必须对步骤 4 返回的数组元素使用相同的顺序。”?是的,那一定是个 bug(它也在最终规范中),是 ES5 的遗留问题(同样的“if”,略有不同的措辞)。或者它可能指的是宿主对象(而不是 JavaScript 对象)。 - T.J. Crowder

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接