@@ -12,8 +12,8 @@ const { TOKEN, constructorError } = require('./lazy-common.js');
1212// via `Object.getOwnPropertySymbols` or `Reflect.ownKeys`. Therefore user code cannot unwrap the proxy.
1313const ARRAY = Symbol ( ) ;
1414
15- // Function to get element from an array. Initialized in class static block below.
16- let getElement ;
15+ // Functions to get length of and get element from an array. Initialized in class static block below.
16+ let getLength , getElement ;
1717
1818/**
1919 * An array of AST nodes where elements are deserialized lazily upon access.
@@ -44,8 +44,8 @@ class NodeArray extends Array {
4444 constructor ( pos , length , stride , construct , ast ) {
4545 if ( ast ?. token !== TOKEN ) constructorError ( ) ;
4646
47- super ( length ) ;
48- this . #internal = { pos, ast, stride, construct } ;
47+ super ( ) ;
48+ this . #internal = { pos, length , ast, stride, construct } ;
4949 return new Proxy ( this , PROXY_HANDLERS ) ;
5050 }
5151
@@ -55,24 +55,19 @@ class NodeArray extends Array {
5555 // Override `values` method with a more efficient one that avoids going via proxy for every iteration.
5656 // TODO: Benchmark to check that this is actually faster.
5757 values ( ) {
58- // Get actual `NodeArray`. `this` is a proxy.
59- const arr = this [ ARRAY ] ;
60- return new NodeArrayValuesIterator ( arr . #internal, arr . length ) ;
58+ return new NodeArrayValuesIterator ( this [ ARRAY ] . #internal) ;
6159 }
6260
6361 // Override `keys` method with a more efficient one that avoids going via proxy for every iteration.
6462 // TODO: Benchmark to check that this is actually faster.
6563 keys ( ) {
66- // `this` is a proxy, but proxy will pass through getting `this.length` to the underlying `NodeArray`
67- return new NodeArrayKeysIterator ( this . length ) ;
64+ return new NodeArrayKeysIterator ( this [ ARRAY ] . #internal. length ) ;
6865 }
6966
7067 // Override `entries` method with a more efficient one that avoids going via proxy for every iteration.
7168 // TODO: Benchmark to check that this is actually faster.
7269 entries ( ) {
73- // Get actual `NodeArray`. `this` is a proxy.
74- const arr = this [ ARRAY ] ;
75- return new NodeArrayEntriesIterator ( arr . #internal, arr . length ) ;
70+ return new NodeArrayEntriesIterator ( this [ ARRAY ] . #internal) ;
7671 }
7772
7873 // This method is overwritten with reference to `values` method below.
@@ -88,36 +83,35 @@ class NodeArray extends Array {
8883 * @returns {NodeArray } - `NodeArray` containing slice of this one
8984 */
9085 slice ( start , end ) {
91- // Get actual `NodeArray`. ` this` is a proxy.
92- const arr = this [ ARRAY ] ;
86+ const internal = this [ ARRAY ] . #internal ,
87+ { length } = internal ;
9388
9489 start = toInt ( start ) ;
9590 if ( start < 0 ) {
96- start = arr . length + start ;
91+ start = length + start ;
9792 if ( start < 0 ) start = 0 ;
9893 }
9994
10095 if ( end === void 0 ) {
101- end = arr . length ;
96+ end = length ;
10297 } else {
10398 end = toInt ( end ) ;
10499 if ( end < 0 ) {
105- end = arr . length + end ;
100+ end += length ;
106101 if ( end < 0 ) end = 0 ;
107- } else if ( end > arr . length ) {
108- end = arr . length ;
102+ } else if ( end > length ) {
103+ end = length ;
109104 }
110105 }
111106
112- let length = end - start ;
113- if ( length <= 0 || start >= arr . length ) {
107+ let sliceLength = end - start ;
108+ if ( sliceLength <= 0 || start >= length ) {
114109 start = 0 ;
115- length = 0 ;
110+ sliceLength = 0 ;
116111 }
117112
118- const internal = arr . #internal,
119- { stride } = internal ;
120- return new NodeArray ( internal . pos + start * stride , length , stride , internal . construct , internal . ast ) ;
113+ const { stride } = internal ;
114+ return new NodeArray ( internal . pos + start * stride , sliceLength , stride , internal . construct , internal . ast ) ;
121115 }
122116
123117 // Make `console.log` deserialize all elements.
@@ -128,16 +122,23 @@ class NodeArray extends Array {
128122 }
129123
130124 static {
125+ /**
126+ * Get length of `NodeArray`.
127+ * @param {NodeArray } arr - `NodeArray` object
128+ * @returns {number } - Array length
129+ */
130+ getLength = arr => arr . #internal. length ;
131+
131132 /**
132133 * Get element of `NodeArray` at index `index`.
133- * `index` must be in bounds (i.e. `< arr.length`).
134134 *
135135 * @param {NodeArray } arr - `NodeArray` object
136136 * @param {number } index - Index of element to get
137- * @returns {* } - Element at index `index`
137+ * @returns {*|undefined } - Element at index `index`, or `undefined` if out of bounds
138138 */
139139 getElement = ( arr , index ) => {
140140 const internal = arr . #internal;
141+ if ( index >= internal . length ) return void 0 ;
141142 return ( 0 , internal . construct ) ( internal . pos + index * internal . stride , internal . ast ) ;
142143 } ;
143144 }
@@ -154,13 +155,13 @@ module.exports = NodeArray;
154155class NodeArrayValuesIterator {
155156 #internal;
156157
157- constructor ( arrInternal , length ) {
158+ constructor ( arrInternal ) {
158159 const { ast, pos, stride } = arrInternal || { } ;
159160 if ( ast ?. token !== TOKEN ) constructorError ( ) ;
160161
161162 this . #internal = {
162163 pos,
163- endPos : pos + length * stride ,
164+ endPos : pos + arrInternal . length * stride ,
164165 ast,
165166 construct : arrInternal . construct ,
166167 stride,
@@ -211,13 +212,13 @@ class NodeArrayKeysIterator {
211212class NodeArrayEntriesIterator {
212213 #internal;
213214
214- constructor ( arrInternal , length ) {
215+ constructor ( arrInternal ) {
215216 const { ast } = arrInternal || { } ;
216217 if ( ast ?. token !== TOKEN ) constructorError ( ) ;
217218
218219 this . #internal = {
219220 index : 0 ,
220- length,
221+ length : arrInternal . length ,
221222 pos : arrInternal . pos ,
222223 ast,
223224 construct : arrInternal . construct ,
@@ -252,34 +253,35 @@ const PROXY_HANDLERS = {
252253 // Return `true` for indexes which are in bounds.
253254 // e.g. `'0' in arr`.
254255 has ( arr , key ) {
255- if ( isIndex ( key ) ) return key * 1 < arr . length ;
256+ if ( isIndex ( key ) ) return key * 1 < getLength ( arr ) ;
256257 return Reflect . has ( arr , key ) ;
257258 } ,
258259
259- // Get entries which are in bounds .
260+ // Get elements and length .
260261 get ( arr , key ) {
261262 // Methods of `NodeArray` are called with `this` being the proxy, rather than the `NodeArray` itself.
262263 // They can "unwrap" the proxy by getting `this[ARRAY]`.
263264 if ( key === ARRAY ) return arr ;
264-
265- if ( isIndex ( key ) ) {
266- key *= 1 ;
267- if ( key >= arr . length ) return void 0 ;
268- return getElement ( arr , key ) ;
269- }
265+ if ( key === 'length' ) return getLength ( arr ) ;
266+ if ( isIndex ( key ) ) return getElement ( arr , key * 1 ) ;
270267
271268 return Reflect . get ( arr , key ) ;
272269 } ,
273270
274- // Get descriptors which are in bounds .
271+ // Get descriptors for elements and length .
275272 getOwnPropertyDescriptor ( arr , key ) {
273+ if ( key === 'length' ) {
274+ // Cannot return `writable: false` unfortunately
275+ return { value : getLength ( arr ) , writable : true , enumerable : false , configurable : false } ;
276+ }
277+
276278 if ( isIndex ( key ) ) {
277- key *= 1 ;
278- if ( key >= arr . length ) return void 0 ;
279+ const value = getElement ( arr , key * 1 ) ;
280+ if ( value === void 0 ) return void 0 ;
279281 // Cannot return `configurable: false` unfortunately
280- return { value : getElement ( arr , key ) , writable : false , enumerable : true , configurable : true } ;
282+ return { value, writable : false , enumerable : true , configurable : true } ;
281283 }
282- // Cannot return `writable: false` for `length` property unfortunately
284+
283285 return Reflect . getOwnPropertyDescriptor ( arr , key ) ;
284286 } ,
285287
@@ -304,8 +306,9 @@ const PROXY_HANDLERS = {
304306
305307 // Get keys, including element indexes.
306308 ownKeys ( arr ) {
307- const keys = [ ] ;
308- for ( let i = 0 ; i < arr . length ; i ++ ) {
309+ const keys = [ ] ,
310+ length = getLength ( arr ) ;
311+ for ( let i = 0 ; i < length ; i ++ ) {
309312 keys . push ( i + '' ) ;
310313 }
311314 keys . push ( ...Reflect . ownKeys ( arr ) ) ;
0 commit comments