对于对 v8 实现感兴趣的人,这里是 source。因为unshift 接受任意数量的参数,所以数组将自行移动以容纳所有参数。
UnshiftImpl 最终以 start_position 的 AT_START 调用 AddArguments,这会将其踢到 else statement
// If the backing store has enough capacity and we add elements to the
// start we have to shift the existing objects.
Isolate* isolate = receiver->GetIsolate();
Subclass::MoveElements(isolate, receiver, backing_store, add_size, 0,
length, 0, 0);
并将其带到MoveElements。
static void MoveElements(Isolate* isolate, Handle<JSArray> receiver,
Handle<FixedArrayBase> backing_store, int dst_index,
int src_index, int len, int hole_start,
int hole_end) {
Heap* heap = isolate->heap();
Handle<BackingStore> dst_elms = Handle<BackingStore>::cast(backing_store);
if (len > JSArray::kMaxCopyElements && dst_index == 0 &&
heap->CanMoveObjectStart(*dst_elms)) {
// Update all the copies of this backing_store handle.
*dst_elms.location() =
BackingStore::cast(heap->LeftTrimFixedArray(*dst_elms, src_index))
->ptr();
receiver->set_elements(*dst_elms);
// Adjust the hole offset as the array has been shrunk.
hole_end -= src_index;
DCHECK_LE(hole_start, backing_store->length());
DCHECK_LE(hole_end, backing_store->length());
} else if (len != 0) {
WriteBarrierMode mode = GetWriteBarrierMode(KindTraits::Kind);
dst_elms->MoveElements(heap, dst_index, src_index, len, mode);
}
if (hole_start != hole_end) {
dst_elms->FillWithHoles(hole_start, hole_end);
}
}
我还想指出,v8 有一个不同的 element kinds 概念,具体取决于数组包含的内容。这也会影响性能。
实际上很难说性能是什么,因为实际上它取决于传递的元素类型,数组中有多少孔等。如果我再深入研究一下,也许我可以给出一个明确的答案,但在一般我假设因为unshift需要在数组中分配更多空间,一般你可以假设它是O(N)(将根据元素的数量线性缩放)但如果我错了请有人纠正我。