I have two array subclasses: Nodes and Beacons. When I run .concat on two of their instances, it creates a new array with 2 elements: the entire nodes array instance, and the entire beacons array instance. What should I do to make it work as expected?
Nodes.js
mgm.Nodes = function() {
Array.apply(this, arguments);
this.fetch();
};
mgm.Nodes.prototype = Object.create(Array.prototype);
mgm.Nodes.prototype.constructor = mgm.Nodes;
mgm.Nodes.prototype.create = function(data) {
//mgm.Node is an object and should be fine to replace with Object for testing purposes
var node = new mgm.Node(data);
this.push(node);
return node;
};
mgm.Nodes.prototype.get = function(id) {
};
mgm.Nodes.prototype.fetch = function() {
var n = 20;
for (var i = 0; i < n; i++) {
var data = {
id: i,
attributes: {name: undefined,}
};
this.create(data);
}
};
mgm.Nodes.prototype.remove = function(node) {
return this.splice(this.indexOf(node), 1)[0];
};
mgm.Nodes.prototype.update = function(node) {
// TODO: bind this to node.on('save')
};
Beacons.js
mgm.Beacons = function() {
this.fetch();
};
mgm.Beacons.prototype = Object.create(Array.prototype);
mgm.Beacons.constructor = mgm.Beacons;
mgm.Beacons.prototype.create = function(data) {
//mgm.Beacon is an object and should be fine to replace with Object for testing purposes
var beacon = new mgm.Beacon(data);
this.push(beacon);
return beacon;
};
mgm.Beacons.prototype.fetch = function() {
this.create({x: 200, y: 150, fixed: true, tag: ''});
};
Running this results in a length 2 array (expected 21), where the 0th element has a length of 20:
var nodes = new Nodes();
var beacons = new Beacons();
console.log(nodes.concat(beacons));
It creates a new array with 2 elements: the entire nodes array instance, and the entire beacons array instance.
That's because they are no array instances. See what the concat
method does to determine whether the to-be-concatenated objects are concatenated item-by-item:
If the value of the [[Class]] internal property of E is "Array", then
[iterate E and push each single element]
else [put E as a whole on the result array]
Your Beacons
and Nodes
might inherit from Array.prototype
, but they are simple objects - no special [[Class]], no auto-adjusting length
property. Btw, Array.apply(this, arguments);
does not work as expected, it simply creates a new Array. Use this.push.apply(this, arguments);
.
What should I do to make it work as expected?
You can overwrite concat
with your own implementation:
mgm.Nodes.prototype.concat = mgm.Beacons.prototype.concat = function concat(other) {
var O = Object(this),
A = new Array(), // new this.constructor() ?
n = 0,
items = [O];
items.push.apply(items, arguments);
while (items.length > 0) {
var E = items.shift();
if (typeof E.length == "number") { // not: Array.isArray(E)
var k = 0,
len = E.length;
while (k < len) {
var P = ""+k;
if (Object.prototype.hasOwnProperty.call(E, P)) {
var subElement = E[P];
A[n] = subElement;
n++;
}
k++;
}
} else { // E is not Array-like
A[n] = E;
n++;
}
}
return A;
};
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.