我正在寻找替换或添加数组元素而不删除原始引用的最佳方法。这是设置:
var a = [], b = [], c, i, obj;
for ( i = 0; i < 100000; i++ ) { a[ i ] = i; b[ i ] = 10000 - i; }
obj.data_list = a;
现在我们想连接b INTO a而不更改对a的引用,因为它在obj.data_list中使用。这是一种方法:
for ( i = 0; i < b.length; i++ ) { a.push( b[ i ] ); }
这似乎是一个有点terser和8x(在V8上)更快的方法:
a.splice.apply( a, [ a.length, 0 ].concat( b ) );
我发现这在迭代“就地”数组时很有用,并且不想在我去的时候触摸元素(一个好习惯)。我用初始参数启动一个新数组(让我们称之为keep_list),然后添加我希望保留的元素。最后,我使用此apply方法快速替换截断的数组:
var keep_list = [ 0, 0 ];
for ( i = 0; i < a.length; i++ ){
if ( some_condition ){ keep_list.push( a[ i ] );
}
// truncate array
a.length = 0;
// And replace contents
a.splice.apply( a, keep_list );
此解决方案存在一些问题:
有没有人找到更好的方法?
答案 0 :(得分:1)
可能最有效的方法仍然是使用push
。
var source = [],
newItems = [1, 2, 3];
source.push.apply(source, newItems);
如果达到最大调用堆栈,则可以将操作分成多个批次。
var source = [],
newItems = new Array(500000),
i = 0,
len = newItems.length,
batch;
for (; i < len; i++) newItems[i] = i;
//You need to find a real cross-browser stack size, here I just used 50k
while((batch = newItems.splice(0, 50000)).length) {
source.push.apply(source, batch);
}
console.log(source[499999]);
另请注意,昂贵的操作可能会使浏览器挂起,尤其是在具有慢速JS引擎的旧浏览器中。为了解决这个问题,您可以进一步将流程拆分为较小的批次,并使用setTimeout
让浏览器屏住呼吸。
最后我想到的另一种方法是在数组周围使用一个包装器对象,它允许你直接替换数组,因为你的引用将通过对象保留。
var arrWrapper = { list: [] },
obj1 = { items: arrWrapper },
obj2 = { items: arrWrapper };
//update the array
obj2.items.list = [1, 2, 3, 4];
//access the array
obj1.items.list;
唯一的限制是避免直接引用arrWrapper.list
。
注意:如果您仅定位现代浏览器,则可以使用WebWorkers
。但据我所知,您只能传递序列化数据,这意味着工作人员无法直接修改源数组。