24

Say I have an object which assigns properties based off the return value of a function:

var i = 0;

var f = function() { return ++i; }

var foo = {
            a:f(),
            b:f(),
            c:f()
          };

Is it guaranteed that foo.a will be 1, foo.b will be 2, and foo.c will be 3? I know that JS doesn't guarantee order when you iterate over an object, what about assignment?

Is it specified in the JS specification somewhere? I'm only asking for educational reasons.

Thanks.

jdw
  • 1,533
  • 3
  • 17
  • 26

5 Answers5

19

Standard ECMA-262 (5.1) - Section 11.1.5 - Object Initialiser

The production PropertyNameAndValueList : PropertyNameAndValueList , PropertyAssignment is evaluated as follows:

1. Let obj be the result of evaluating PropertyNameAndValueList.
2. Let propId be the result of evaluating PropertyAssignment.
...
5. Call the [[DefineOwnProperty]] internal method of obj with arguments propId.name, propId.descriptor, and false.
6. Return obj.

So yes, the order is enforced by the standard.

Karoly Horvath
  • 94,607
  • 11
  • 117
  • 176
  • Up-to-date specification: [Runtime Semantics: PropertyDefinitionEvaluation](//tc39.es/ecma262/#sec-runtime-semantics-propertydefinitionevaluation). The production _PropertyDefinitionList_ : _PropertyDefinitionList_ `,` _PropertyDefinition_ is evaluated recursively with 1. Perform ? PropertyDefinitionEvaluation of _PropertyDefinitionList_ with argument _object_. 2. Perform ? PropertyDefinitionEvaluation of _PropertyDefinition_ with argument _object_. – Sebastian Simon Jan 13 '23 at 00:30
2

From the ECMAScript 6 wiki, which will define the new version of JS:

When a scope (Block, FunctionBody, Program, ModuleBody, etc.) is entered, the variables declared by all immediately contained function and class declarations are bound to their respective functions and classes. Then all class bodies are executed in textual order. A class body defines and initializes class-wide properties once when the class definition is evaluated. This includes properties on the constructor function (the “class” itself) and on its prototype property. These initializations happen in textual order.

Your source has arrived! JavaScript object properties are initialized in textual order on objects. Arrays do not (currently) always follow this rule.

Source: http://wiki.ecmascript.org/doku.php?id=harmony:classes

I will edit this post when I find the reference in ECMAScript 5, though I am certain it is there.

Edit: Found it

ECMAScript 5 does have it: http://www.ecma-international.org/ecma-262/5.1/#sec-15.2.3.7 .

If an implementation defines a specific order of enumeration for the for-in statement, that same enumeration order must be used to order the list elements in step 3 of this algorithm.

This defines the calls to DefineOwnProperty and therefore the position of the properties in the internal table.

Sébastien Renauld
  • 19,203
  • 2
  • 46
  • 66
  • OP did neither ask about ES6 classes, nor about enumeration or in for-in-loops. – Bergi Apr 24 '13 at 19:59
  • @Bergi: `Object.defineProperties ( O, Properties )` never was for-in loops, and ES6 classes directly take from ES5 objects in most of their uses and properties. – Sébastien Renauld Apr 24 '13 at 20:01
0

Assignment is always in order. It is just the way the code is found, interpreted and executed.

Deathspike
  • 8,582
  • 6
  • 44
  • 82
0

Yes, you are guaranteed that a will be 1, b will be 2, etc. Each f() will be interpreted in the order you wrote them.

mchail
  • 821
  • 5
  • 12
-1

I don't have an official source to quote, but let's just use a little common sense.

What if assignment wasn't done in order? You could never know which value would be assigned to which property, making the object structure useless (at least when using the object literal syntax).

It makes no difference if it's a function call, or a primitive literal, or some other value. If it wasn't guaranteed to happen in order, it just wouldn't work.


After doing a quick search of the term left to right in ECMAScript 5, here are some results if it helps you:

7 Lexical Conventions

The source text of an ECMAScript program is first converted into a sequence of input elements, which are tokens, line terminators, comments, or white space. The source text is scanned from left to right, repeatedly taking the longest possible sequence of characters as the next input element.

11.8.5 The Abstract Relational Comparison Algorithm

...It is necessary because ECMAScript specifies left to right evaluation of expressions.

Annex D (informative) Corrections and Clarifications in the 5th Edition with Possible 3rd Edition Compatibility Impact

ECMAScript generally uses a left to right evaluation order, however the Edition 3 specification language for the > and <= operators resulted in a partial right to left order. The specification has been corrected for these operators such that it now specifies a full left to right evaluation order.

grasp
  • 68
  • 3
  • 1
    LTR in this case is about the evaluation order of statements, not the property order. What they mean by LTR is "a > b" becauses "a greater than b" and not the other way around. I have provided the correct paragraphs for both ECMAS5 and 6. – Sébastien Renauld Apr 24 '13 at 19:41
  • @SébastienRenauld: This is a general reference to evaluation order of expressions, though the main point is unchanged. If the order couldn't be relied upon, object literal syntax would be useless. – grasp Apr 24 '13 at 19:57
  • @SébastienRenauld: And your ECMAScript 5 reference isn't relevant to the question being asked. An ES implementation is free to define an order of enumeration when using `for-in`. The definition could be reliable or unreliable by design. You're quoting the definition of `defineProperties`, which simply states that if an order of enumeration is defined, that order will be applied in the creation of the properties. This isn't related at all to object literal syntax. – grasp Apr 24 '13 at 20:02
  • The order of enumeration is acquired from two steps up, section 11, and that gets it from the JSON literal definition. I have provided a link to where the actual order is explicitely respected - the final step - not to every step along the way. – Sébastien Renauld Apr 24 '13 at 20:03
  • ...and if you think about it, it makes sense. When you use `.defineProperties()`, you're passing an object literal to create the properties. The object literal isn't the target object itself. This object literal needs to be enumerated to get its information in order to define the new properties on the target object. So if an order of enumeration is defined by the implementation, it would makes sense that that same order would be honored when internally enumerating the property descriptors. – grasp Apr 24 '13 at 20:06
  • @SébastienRenauld: JavaScript doesn't have anything called "JSON literal" *(aside from having a string literal that adheres to the JSON notation standard)*. – grasp Apr 24 '13 at 20:07
  • There was never a disagreement on this point. However, you still refered to the lexical order within a statement. – Sébastien Renauld Apr 24 '13 at 20:07
  • http://www.ecma-international.org/ecma-262/5.1/#sec-5.1.5 . Sorry if I was unclear. – Sébastien Renauld Apr 24 '13 at 20:08
  • @SébastienRenauld: I don't understand why you're referencing JSON here. JSON is just a text based data interchange format. Other than the fact that it borrowed its syntax from a subset of JavaScript's object literal syntax, it really has nothing to do with the evaluation of JavaScript programs. – grasp Apr 24 '13 at 20:11
  • I may be completely wrong about the actual item passed two steps up from defineProperties. However, I am pretty sure it was an object literal. Not quite sure on this point, hence why I tentatively linked the bit that, I thought, was three steps up. Most possibly wrong. – Sébastien Renauld Apr 24 '13 at 20:12
  • @SébastienRenauld: If by two steps up, you mean `Object.create`, then that's just a method that's similar to `Object.defineProperties`, except that it creates a new object, and lets you set the internal `[[Prototype]]` property during its creation. The second argument for both methods will behave identically *(except of course that with `Object.create` you have a clean slate)*. That argument can be any object that holds the property descriptors desired for the target object. The descriptors don't necessarily need to be created using object literal syntax, but usually that's the case. – grasp Apr 24 '13 at 20:20
  • Okay. I thought the object literal syntax was compulsory at this point. I stand corrected - thank you :-) – Sébastien Renauld Apr 24 '13 at 20:35