0

Creating an array with objects of property descriptors like indexed value object

a = Object.create(Array.prototype, {
    0 : { writable : true, configurable : true, value : 1},
    1 : { writable : true, configurable : true, value : 2},
    2 : { writable : true, configurable : true, value : 3},
    3 : { writable : true, configurable : true, value : 4}
});
//Array {0: 1, 1: 2, 2: 3, 3: 4}
//0: 1
//1: 2
//2: 3
//3: 4
//[[Prototype]]: Array(0)

But why it is not behaving like normal array?

Array.isArray(a) //false
a instanceof Array //true
typeof a.reduce == 'function' //true
a.reduce((previous, current)=> previous+current)
//Uncaught TypeError: Reduce of empty array with no initial value
    at Array.reduce (<anonymous>)
    at <anonymous>:1:3
for(let i of a){
    console.log(i);
}
//prints nothing
2

2 Answers 2

1

You did not give your array a .length property.

let a = Object.create(Array.prototype, {
    0 : { writable : true, configurable : true, value : 1},
    1 : { writable : true, configurable : true, value : 2},
    2 : { writable : true, configurable : true, value : 3},
    3 : { writable : true, configurable : true, value : 4},
    length: { writable : true, configurable : true, value : 4}
});

The Array.isArray() function returns false because your object is not an instance of Array; it is an object that shares the Array prototype, but it is not an Array instance. Also, as noted in a comment by an esteemed colleague, your properties should also be enumerable.

Adding length will make your .reduce() work, but you still won't have an actual Array; many other things won't work.

Sign up to request clarification or add additional context in comments.

11 Comments

Also, the element properties should be enumerable: true. But it still won't be an array. length isn't really a data property, for one thing, even though its descriptor claims it is.
@T.J.Crowder I wondered that, and you're of course almost certainly correct, but at least in Node once I added the length, the .reduce() call worked. I guess that's because inside .reduce() it's (essentially) a simple for loop, so they don't need to be enumerable.
@T.J.Crowder right; it would help to know why the OP is trying to do this.
It is part of the intrinsic behavior of Array instances. If you would take the time to explain what you are trying to do, you would probably get more assistance.
@PriyabrataChattaraj - It lives in the JavaScript engine. Arrays are exotic objects with atypical behaviors, details in the specification. If you want to create a psuedo-array, you'd have to use a Proxy (and you still couldn't fool Array.isArray).
|
0

It's not working because length is not defined here.
reduce() and for of need length property to work.

a = Object.create(Array.prototype, {
    0 : { writable : true, configurable : true, value : 1},
    1 : { writable : true, configurable : true, value : 2},
    2 : { writable : true, configurable : true, value : 3},
    3 : { writable : true, configurable : true, value : 4}
});
//Array {0: 1, 1: 2, 2: 3, 3: 4}
a.length = 4
//4
for(let i of a)
    console.log(i);
// 1
// 2
// 3
// 4

But it will still not fool the Array.isArray()

Array.isArray(a)
//false


This is because the hidden machanisim of "Execotic Object" Exotic Object can not be created with Object.create() or new Constructor(), this needs to be extended with javascript class to create subclass ref
Here the internal mechanisim for Array is writtine inside JS Engine itself so it untouched.

Exotic Objects

Are any objects that have different internal implementations are Exotic Object, for example: Array, Proxy, String, Arguments, Module
So, in Javascript objects can be categorized into Ordinary Objects and Exotic Objects.

Ordinary objects are normal object we encounter that doesn't show any unexpected behavior. example: any objects initialized with {}

Let's see some exotic object's behavior


const arr = []
//undefined
arr[0] = 10
//10
arr.length
//1
arr[NaN] = 18
//18
arr[null] = 20
//20
arr.length
//1
arr[50] = 50
//50
arr.length
//51
console.log(arr)
//[10, empty × 49, 50, NaN: 18, null: 20]
//0: 10 50: 50 NaN: 18 null: 20 length: 51 [[Prototype]]: Array(0)
arr.length=0
//0
console.log(arr)
//[NaN: 18, null: 20]
//NaN: 18 null: 20 length: 0 [[Prototype]]: Array(0)

Do you wonder why it is happening?
Changing length affects the array elements and changing elements affects the array
This is because array have [[DefineOwnProperty]] different then of that Object.defineProperty()
enter image description here link So, arr[index] the index has to be in the range of 0 to (2^32)-1 and should not be the word length then it will be treated as an index, and length will be updated if index >= length. Else it will be added as a normal object property.
enter image description here link If now index is the word length ArraySetLength function is called and if previous length is writable and new length is greater than previous it will set the length o array as provided and empty cells will be showed as empty by the browser or node.
Esle if new length is smaller it will delete all the element until it encounter an non-configurable element

const arr = [10, 20,30,50]
//undefined
Object.defineProperty(arr,1, {value: 15, configurable : false});
//[10, 15, 30, 50]
arr.length=0
//0
console.log(arr)
//[10, 15]

YouTube video explaination link

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.