如何连接两个子类化数组

How to concat two subclassed arrays?

本文关键字:两个 子类 数组 连接 何连接      更新时间:2023-09-26

我有两个数组子类:节点和信标。 当我在他们的两个实例上运行 .concat 时,它会创建一个包含 2 个元素的新数组:整个节点数组实例和整个信标数组实例。 我应该怎么做才能使其按预期工作?

节点.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')
};

信标.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: ''});
};

运行此操作会导致数组长度为 2(预期为 21),其中第 0 个元素的长度为 20:

var nodes = new Nodes();
var beacons = new Beacons();
console.log(nodes.concat(beacons));

它创建一个包含 2 个元素的新数组:整个节点数组实例和整个信标数组实例。

那是因为它们不是数组实例。了解 concat 方法如何确定要串联的对象是否逐项连接:

如果 E 的 [[Class]] 内部属性的值是 "Array",则

[迭代 E 并推送每个元素]

else [将 E 作为一个整体放在结果数组上]

您的BeaconsNodes可能继承自Array.prototype,但它们是简单的对象 - 没有特殊的[[Class]],没有自动调整length属性。顺便说一句,Array.apply(this, arguments);没有按预期工作,它只是创建一个新的数组。使用this.push.apply(this, arguments); .

我应该怎么做才能使其按预期工作?

您可以使用自己的实现覆盖concat

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;
};