This repository has been archived by the owner on Feb 19, 2020. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 9
/
spec.html
174 lines (164 loc) · 9.79 KB
/
spec.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
<!doctype html>
<meta charset="utf8">
<link rel="stylesheet" href="./spec.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/8.4/styles/github.min.css">
<script src="./spec.js"></script>
<pre class="metadata">
title: For-in enumeration order
stage: 1
contributors: Kevin Gibbons
</pre>
<emu-intro id="sec-intro">
<h1>Introduction</h1>
<p>The order of `for (a in b) ...` is specified in EnumerateObjectProperties, but only loosely. This proposal aims to begin fixing that.</p>
</emu-intro>
<emu-clause id="sec-enumerate-object-properties" aoid="EnumerateObjectProperties">
<h1>EnumerateObjectProperties ( _O_ )</h1>
<p>When the abstract operation EnumerateObjectProperties is called with argument _O_, the following steps are taken:</p>
<emu-alg>
1. Assert: Type(_O_) is Object.
1. Return an Iterator object (<emu-xref href="#sec-iterator-interface"></emu-xref>) whose `next` method iterates over all the String-valued keys of enumerable properties of _O_. The iterator object is never directly accessible to ECMAScript code. The mechanics and order of enumerating the properties is not specified but must conform to the rules specified below.
</emu-alg>
<p>The iterator's `throw` and `return` methods are *null* and are never invoked. The iterator's `next` method processes object properties to determine whether the property key should be returned as an iterator value. Returned property keys do not include keys that are Symbols. Properties of the target object may be deleted during enumeration. A property that is deleted before it is processed by the iterator's `next` method is ignored. If new properties are added to the target object during enumeration, the newly added properties are not guaranteed to be processed in the active enumeration. A property name will be returned by the iterator's `next` method at most once in any enumeration.</p>
<p>Enumerating the properties of the target object includes enumerating properties of its prototype, and the prototype of the prototype, and so on, recursively; but a property of a prototype is not processed if it has the same name as a property that has already been processed by the iterator's `next` method. The values of [[Enumerable]] attributes are not considered when determining if a property of a prototype object has already been processed. The enumerable property names of prototype objects must be obtained by invoking EnumerateObjectProperties passing the prototype object as the argument. EnumerateObjectProperties must obtain the own property keys of the target object by calling its [[OwnPropertyKeys]] internal method. Property attributes of the target object must be obtained by calling its [[GetOwnProperty]] internal method.</p>
<p><ins>In addition, if neither _O_ nor any object in its prototype chain is a Proxy exotic object, Integer-Indexed exotic object, Module Namespace exotic object, or implementation provided exotic object, then the iterator must behave as if it were the iterator given by CreateForInIterator ( _O_ ) until one of the following occurs:</ins></p>
<ul>
<li><ins>the value of the [[Prototype]] internal slot of _O_ or an object in its prototype chain changes,</ins></li>
<li><ins>a property is removed from _O_ or an object in its prototype chain,</ins></li>
<li><ins>a property is added to an object in _O_'s prototype chain, or</ins></li>
<li><ins>the value of the [[Enumerable]] attribute of a property of _O_ or an object in its prototype chain changes.</ins></li>
</ul>
<emu-note>
<p><ins>Rather than implementing the algorithm in <emu-xref href="#sec-%foriniteratorprototype%.next"></emu-xref> directly, engines are expected choose an implementation whose behavior will not deviate from that algorithm unless one of the constraints in the previous paragraph is violated.</ins></p>
<p><ins>For example, the following is an informative definition of an ECMAScript generator function that conforms to these rules:</ins></p>
<pre><code class="javascript">
function* EnumerateObjectProperties(obj) {
const visited = new Set();
for (const key of Reflect.ownKeys(obj)) {
if (typeof key === "symbol") continue;
const desc = Reflect.getOwnPropertyDescriptor(obj, key);
if (desc) {
visited.add(key);
if (desc.enumerable) yield key;
}
}
const proto = Reflect.getPrototypeOf(obj);
if (proto === null) return;
for (const protoKey of EnumerateObjectProperties(proto)) {
if (!visited.has(protoKey)) yield protoKey;
}
}
</code></pre>
</ins></emu-note>
<emu-note><ins>
The list of exotic objects for which implementations are not required to match CreateForInIterator was chosen because implementations historically differed in behavior for those cases, and agreed in all others.
</ins></emu-note>
</emu-clause>
<emu-clause id="sec-for-in-iterator-objects">
<h1>For In Iterator Objects</h1>
<p>A For In Iterator is an object that represents a specific iteration over some specific object. For In Iterator objects are never directly accessible to ECMAScript code; they exist soley to illustrate the behavior of EnumerateObjectProperties.</p>
<emu-clause id="sec-createforiniterator" aoid="CreateForInIterator">
<h1>CreateForInIterator ( _object_ )</h1>
<p>The abstract operation CreateForInIterator with argument _object_ is used to create a For In Iterator object which iterates over the own and inherited enumerable string properties of _object_ in a specific order. It performs the following steps:</p>
<emu-alg>
1. Assert: Type(_object_) is Object.
1. Let _iterator_ be ObjectCreate(%ForInIteratorPrototype%, « [[Object]], [[ObjectWasVisited]], [[VisitedKeys]], [[RemainingKeys]] »).
1. Set _iterator_.[[Object]] to _object_.
1. Set _iterator_.[[ObjectWasVisited]] to *false*.
1. Set _iterator_.[[VisitedKeys]] to a new empty List.
1. Set _iterator_.[[RemainingKeys]] to a new empty List.
1. Return _iterator_.
</emu-alg>
</emu-clause>
<emu-clause id="sec-%foriniteratorprototype%-object">
<h1>The %ForInIteratorPrototype% Object</h1>
<p>The <dfn>%ForInIteratorPrototype%</dfn> object:</p>
<ul>
<li>has properties that are inherited by all For In Iterator Objects.</li>
<li>is an ordinary object.</li>
<li>has a [[Prototype]] internal slot whose value is the intrinsic object %IteratorPrototype%.</li>
<li>is never directly accessible to ECMAScript code.</li>
<li>has the following properties:</li>
</ul>
<emu-clause id="sec-%foriniteratorprototype%.next">
<h1>%ForInIteratorPrototype%.next ( )</h1>
<emu-alg>
1. Let _O_ be the *this* value.
1. Assert: Type(_O_) is Object.
1. Assert: _O_ has all of the internal slots of a For In Iterator Instance (<emu-xref href="#sec-properties-of-for-in-iterator-instances"></emu-xref>).
1. Let _object_ be _O_.[[Object]].
1. Let _visited_ be _O_.[[VisitedKeys]].
1. Let _remaining_ be _O_.[[RemainingKeys]].
1. Repeat,
1. If _O_.[[ObjectWasVisited]] is *false*, then
1. Let _keys_ be ? _object_.[[OwnPropertyKeys]]().
1. For each _key_ of _keys_ in List order, do
1. If Type(_key_) is String, then
1. Append _key_ to _remaining_.
1. Set _O_.[[ObjectWasVisited]] to *true*.
1. Repeat, while _remaining_ is not empty,
1. Remove the first element from _remaining_ and let _r_ be the value of the element.
1. If there does not exist an element _v_ of _visited_ such that SameValue(_r_, _v_) is *true*, then
1. Let _desc_ be ? _object_.[[GetOwnProperty]](_r_).
1. If _desc_ is not *undefined*, then
1. Append _r_ to _visited_.
1. If _desc_.[[Enumerable]] is *true*, return CreateIterResultObject(_r_, *false*).
1. Set _object_ to ? _object_.[[GetPrototypeOf]]().
1. Set _O_.[[Object]] to _object_.
1. Set _O_.[[ObjectWasVisited]] to *false*.
1. If _object_ is *null*, return CreateIterResultObject(*undefined*, *true*).
</emu-alg>
</emu-clause>
</emu-clause>
<emu-clause id="sec-properties-of-for-in-iterator-instances">
<h1>Properties of For In Iterator Instances</h1>
<p>For In Iterator instances are ordinary objects that inherit properties from the %ForInIteratorPrototype% intrinsic object. For In Iterator instances are initially created with the internal slots listed in <emu-xref href="#table-for-in-iterator-instance-slots"></emu-xref>.</p>
<emu-table id="table-for-in-iterator-instance-slots" caption="Internal Slots of For In Iterator Instances">
<table>
<tbody>
<tr>
<th>
Internal Slot
</th>
<th>
Description
</th>
</tr>
<tr>
<td>
[[Object]]
</td>
<td>
The Object value whose properties are being iterated.
</td>
</tr>
<tr>
<td>
[[ObjectWasVisited]]
</td>
<td>
*true* if the iterator has invoked [[OwnPropertyKeys]] on [[Object]], *false* otherwise.
</td>
</tr>
<tr>
<td>
[[VisitedKeys]]
</td>
<td>
A list of String values which have been emitted by this iterator thus far.
</td>
</tr>
<tr>
<td>
[[RemainingKeys]]
</td>
<td>
A list of String values remaining to be emitted for the current object, before iterating those on its prototype (if its prototype is not *null*).
</td>
</tr>
</tbody>
</table>
</emu-table>
</emu-clause>
</emu-clause>
</emu-clause>