How can I return something that looks like an array from a node addon?

69 views Asked by At

I'm implementing a native module for node and trying to return something that looks like an array but is backed by native data. At the moment I'm creating an ObjectTemplate and using SetIndexedPropertyHandler so I can handle attempts to get indexes from JS. This all works, but from JS this just looks like an Object, not an Array. Is there any way I can make this look more like an array?

3

There are 3 answers

0
guest271314 On

You can return Object.entries(object).

The Object.entries() method returns an array of a given object's own enumerable property [key, value] pairs, in the same order as that provided by a for...in loop (the difference being that a for-in loop enumerates properties in the prototype chain as well).

const obj = {a:1, b:2, c:3};

console.log(Object.entries(obj));

0
Amadan On

All arraylike objects must have length. As long as they have that property, you can borrow Array functions and run them on your object (e.g. Array.prototype.forEach.call(obj, ...)), or in ES6 run Array.from on it:

obj = {
  0: "foo",
  1: "bar",
  length: 2
};

// ES5 way to get a real array:
console.log(Array.prototype.slice.call(obj));

// ES6 way to get a real array:
console.log(Array.from(obj));

If you actually want to return an array and not an arraylike object, then I suggest you use array = Array::New() and array->Set(index, element) instead of ObjectTemplate. There's an example in this question.

0
ZachB On

You could consider using a Proxy around a real array, with traps/handlers that interface with your native object. There's a performance penalty to using proxies (don't try to iterate over a proxied array if it's an important, hot code path), but they let you do just about anything.

var _arr = [];
var arraylike = new Proxy(_arr, {
    get: function (target, prop) {
        // Interface with your native object here.
        if (prop === "length") return 20;
        return "hello";
    }
});

// Consume
> arraylike.length
20
> arraylike[5]
"hello"
> arraylike instanceof Array
true
> Array.isArray(arraylike)
true

It's also perfectly valid to prototypically inherit from Array in javascript.