• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# ArkCompiler Subsystem Changelog
2
3## cl.arkcompiler.1 Behavior Change for Property Lookup and Setting on Array
4
5**Access Level**
6
7Public API
8
9**Reason for Change**
10
11According to the ECMAScript specification, when certain properties are queried on Array instances and these properties do not exist on the Array instance itself, the prototype chain should be traversed to perform the query. Some non-StableArrays are mistakenly identified as StableArrays. As a result, the prototype chain query is skipped, and the query result is inconsistent with the expected outcomes defined by the ECMAScript specification.
12
13**Impact of the Change**
14
15This change does not require application adaptation.
16
17**Before**
18
19- Case 1: When an object (o) is an instance of the Array type and (Array.prototype) is modified using specific methods (**fill**, **push**, **splice**, or **unshift**), certain APIs (**concat**, **slice**, **at**, **reduce**, or **reverse**) cannot correctly read elements from (o) on (Array.prototype), returning an incorrect result.
20- Case 2: When a class MyArray inherits from Array and an object (o) is an instance of MyArray, the constructor property on (o) is not correctly invoked, leading to incorrect results when calling **instance of** on (o).
21- Case 3: When a class MyArray inherits from Array, an object (o) is an instance of MyArray, and MyArray.prototype.proto is modified, certain APIs (**concat**, **slice**, **at**, **reduce**, or **reverse**) cannot correctly read elements from (o) on MyArray.prototype.proto, returning an incorrect result.
22- Case 4: When a class MyArray inherits from Array, an object (o) is an instance of MyArray, and an element is inserted to (MyArray.prototype), certain APIs (**concat**, **slice**, **at**, **reduce**, or **reverse**) cannot correctly read elements from (o) on (MyArray.prototype), returning an incorrect result.
23
24```js
25// Case 1:
26function BehaviorChange1() {
27// The following provides four methods to modify Array.prototype, making Array.prototype = [233, 233, 233]. Each code block is parallel.
28// ----------------- Method 1 -----------------
29    let arr1 = new Array(10);
30    arr1.__proto__.length = 3;
31    arr1.__proto__.fill(233, 0, 3);
32// ----------------- Method 1 -----------------
33
34// ----------------- Method 2 -----------------
35    let arr1 = new Array(10);
36    arr1.__proto__.push(233, 233, 233);
37// ----------------- Method 2 -----------------
38
39// ----------------- Method 3 -----------------
40    let arr1 = new Array(10);
41    arr1.__proto__.length = 3;
42    arr1.__proto__.splice(1, 0, 233, 233, 233);
43// ----------------- Method 3 -----------------
44
45// ----------------- Method 4 -----------------
46    let arr1 = new Array(10);
47    arr1.__proto__.unshift(233, 233, 233);
48// ----------------- Method 4 -----------------
49
50    let arr2 = new Array(10);
51    let arr3 = arr1.concat(arr2);
52    print(arr3[11]); // Output: undefined, non-compliant
53
54    let arr4 = arr1.slice(1);
55    print(arr4[0]); // Output: undefined, non-compliant
56
57    let res = arr1.at(1);
58    print(res); // Output: undefined, non-compliant
59
60    const sum = arr1.reduce((accumulator, currentValue) => {
61        return accumulator + currentValue;
62    })
63    print(sum); // Output: undefined, non-compliant
64
65    arr1.reverse();
66    print(arr1[1]); // Output: undefined, non-compliant
67}
68BehaviorChange1();
69
70// Case 2:
71function BehaviorChange2() {
72    class MyArray extends Array {}
73    let custom = new MyArray(1, 2, 3);
74    let result1 = custom.concat([4, 5]);
75    print(result1 instanceof MyArray); // Output: false, non-compliant
76
77    let result2 = custom.slice(1);
78    print(result2 instanceof MyArray); // Output: false, non-compliant
79}
80BehaviorChange2()
81
82// Case 3:
83function BehaviorChange3() {
84    class MyArray extends Array {}
85    let arr1 = new MyArray(10);
86    MyArray.prototype.__proto__ = [233, 233, 233];
87    let arr2 = new Array(10);
88    let arr3 = arr1.concat(arr2);
89    print(arr3[1]); // Output: undefined, non-compliant
90
91    let arr4 = arr1.slice(1);
92    print(arr4[0]); // Output: undefined, non-compliant
93
94    let res = arr1.at(1);
95    print(res); // Output: undefined, non-compliant
96
97    const sum = arr1.reduce((accumulator, currentValue) => {
98        return accumulator + currentValue;
99    })
100    print(sum); // Output: undefined, non-compliant
101
102    arr1.reverse();
103    print(arr1[1]); // Output: undefined, non-compliant
104}
105BehaviorChange3();
106
107// Case 4:
108function BehaviorChange4() {
109    class MyArray extends Array {}
110    let arr1 = new MyArray(10);
111    MyArray.prototype[0] = 233;
112    MyArray.prototype[1] = 233;
113    MyArray.prototype[2] = 233;
114
115    let arr2 = new Array(10);
116    let arr3 = arr1.concat(arr2);
117    print(arr3[1]); // Output: undefined, non-compliant
118
119    let arr4 = arr1.slice(1);
120    print(arr4[0]); // Output: undefined, non-compliant
121
122    let res = arr1.at(1);
123    print(res); // Output: undefined, non-compliant
124
125    const sum = arr1.reduce((accumulator, currentValue) => {
126        return accumulator + currentValue;
127    })
128    print(sum); // Output: undefined, non-compliant
129
130    arr1.reverse();
131    print(arr1[1]); // Output: undefined, non-compliant
132}
133BehaviorChange4();
134```
135**After change**
136
137- Case 1: When an object (o) is an instance of the Array type and (Array.prototype) is modified using specific methods (**fill**, **push**, **splice**, or **unshift**), the APIs (**concat**, **slice**, **at**, **reduce**, or **reverse**) can correctly read elements from (o) on (Array.prototype), returning the correct result. (incompatible change)
138- Case 2: When a class MyArray inherits from Array and an object (o) is an instance of MyArray, the constructor property on (o) is not correctly invoked, leading to correct results when calling **instance of** on (o). (incompatible change)
139- Case 3: When a class MyArray inherits from Array, an object (o) is an instance of MyArray, and MyArray.prototype.proto is modified, the APIs (**concat**, **slice**, **at**, **reduce**, or **reverse**) can correctly read elements from (o) on MyArray.prototype.proto, returning the correct result. (incompatible change)
140- Case 4: When a class MyArray inherits from Array, an object (o) is an instance of MyArray, and an element is inserted to (MyArray.prototype), the APIs (**concat**, **slice**, **at**, **reduce**, or **reverse**) can correctly read elements from (o) on (MyArray.prototype), returning the correct result. (incompatible change)
141
142```js
143// Case 1:
144function BehaviorChange1() {
145// The following provides four methods to modify Array.prototype, making Array.prototype = [233, 233, 233]. Each code block is parallel.
146// ----------------- Method 1 -----------------
147    let arr1 = new Array(10);
148    arr1.__proto__.length = 3;
149    arr1.__proto__.fill(233, 0, 3);
150// ----------------- Method 1 -----------------
151
152// ----------------- Method 2 -----------------
153    let arr1 = new Array(10);
154    arr1.__proto__.push(233, 233, 233);
155// ----------------- Method 2 -----------------
156
157// ----------------- Method 3 -----------------
158    let arr1 = new Array(10);
159    arr1.__proto__.length = 3;
160    arr1.__proto__.splice(1, 0, 233, 233, 233);
161// ----------------- Method 3 -----------------
162
163// ----------------- Method 4 -----------------
164    let arr1 = new Array(10);
165    arr1.__proto__.unshift(233, 233, 233);
166// ----------------- Method 4 -----------------
167
168    let arr2 = new Array(10);
169    let arr3 = arr1.concat(arr2);
170    print(arr3[11]); // Output: 233, compliant. concat traverses the prototype chain when the property is not found on the instance.
171
172    let arr4 = arr1.slice(1);
173    print(arr4[0]); // Output: 233, compliant. slice traverses the prototype chain when the property is not found on the instance.
174
175    let res = arr1.at(1);
176    print(res); // Output: 233, compliant. at traverses the prototype chain when the property is not found on the instance.
177
178    const sum = arr1.reduce((accumulator, currentValue) => {
179        return accumulator + currentValue;
180    })
181    print(sum); // Output: 699, compliant. reduce traverses the prototype chain when the property is not found on the instance.
182
183    arr1.reverse();
184    print(arr1[1]); // Output: 233, compliant. reverse traverses the prototype chain when the property is not found on the instance.
185}
186BehaviorChange1();
187
188// Case 2:
189function BehaviorChange2() {
190    class MyArray extends Array {}
191    let custom = new MyArray(1, 2, 3);
192    let result1 = custom.concat([4, 5]);
193    print(result1 instanceof MyArray); // Output: true, compliant. constructor on custom is correctly called.
194
195    let result2 = custom.slice(1);
196    print(result2 instanceof MyArray); // Output: true, compliant. constructor on custom is correctly called.
197}
198BehaviorChange2()
199
200// Case 3:
201function BehaviorChange3() {
202    class MyArray extends Array {}
203    let arr1 = new MyArray(10);
204    MyArray.prototype.__proto__ = [233, 233, 233];
205    let arr2 = new Array(10);
206    let arr3 = arr1.concat(arr2);
207    print(arr3[1]); // Output: 233, compliant. concat traverses the prototype chain when the property is not found on the instance.
208
209    let arr4 = arr1.slice(1);
210    print(arr4[0]); // Output: 233, compliant. slice traverses the prototype chain when the property is not found on the instance.
211
212    let res = arr1.at(1);
213    print(res); // Output: 233, compliant. at traverses the prototype chain when the property is not found on the instance.
214
215    const sum = arr1.reduce((accumulator, currentValue) => {
216        return accumulator + currentValue;
217    })
218    print(sum); // Output: 233, compliant. reduce traverses the prototype chain when the property is not found on the instance.
219
220    arr1.reverse();
221    print(arr1[1]); // Output: 233, compliant. reverse traverses the prototype chain when the property is not found on the instance.
222}
223BehaviorChange3();
224
225// Case 4:
226function BehaviorChange4() {
227    class MyArray extends Array {}
228    let arr1 = new MyArray(10);
229    MyArray.prototype[0] = 233;
230    MyArray.prototype[1] = 233;
231    MyArray.prototype[2] = 233;
232
233    let arr2 = new Array(10);
234    let arr3 = arr1.concat(arr2);
235    print(arr3[1]); // Output: 233, compliant. concat traverses the prototype chain when the property is not found on the instance.
236
237    let arr4 = arr1.slice(1);
238    print(arr4[0]); // Output: 233, compliant. slice traverses the prototype chain when the property is not found on the instance.
239
240    let res = arr1.at(1);
241    print(res); // Output: 233, compliant. at traverses the prototype chain when the property is not found on the instance.
242
243    const sum = arr1.reduce((accumulator, currentValue) => {
244        return accumulator + currentValue;
245    })
246    print(sum); // Output: 699, compliant. reduce traverses the prototype chain when the property is not found on the instance.
247
248    arr1.reverse();
249    print(arr1[1]); // Output: 233, compliant. reverse traverses the prototype chain when the property is not found on the instance.
250}
251BehaviorChange4();
252
253
254```
255
256**Start API Level**
257
258API 9
259
260**Change Since**
261
262OpenHarmony 5.1.0.45
263
264**Key API/Component Changes**
265
266**instance of**, **concat**, **slice**, **at**, **reduce**, and **reverse** APIs in Array
267
268**Adaptation Guide**
269
270When looking up properties on Array, pay attention to the changes in return values.
271