JS之splice()方法刨根問底

目錄

語法

參數

返回值

技術細節

瀏覽器支持 

實例

源碼


今天在使用JS處理字符串數組尋找好用的方法時,發現了一位全能選手splice(),爲什麼說它是全能選手呢?因爲它可以刪除元素,也可以添加元素,而且還可以同時進行刪除和添加元素的操作,666啊,接下來讓我們瞭解一下這位神奇的朋友。

先看基本語法:

語法

array.splice(index,howmany,item1,.....,itemX)

參數

參數 描述
index 必需。規定從何處添加/刪除元素。
該參數是開始插入和(或)刪除的數組元素的下標,必須是數字。
howmany 可選。規定應該刪除多少元素。必須是數字,但可以是 "0"。
如果未規定此參數,則刪除從 index 開始到原數組結尾的所有元素。
item1, ..., itemX 可選。要添加到數組的新元素

返回值

Type 描述
Array 如果從 arrayObject 中刪除了元素,則返回的是含有被刪除的元素的數組。

技術細節

JavaScript 版本: 1.2

瀏覽器支持 

基本上所有主要瀏覽器都支持splice()方法,比如IE、Firefox、歐朋、Chrome、Safari等。

實例

在本例中我們將刪除位於 index=3 的元素,並添加一個新元素來替代被刪除的元素:

var arr = new Array(6)
arr[0] = "Geo"
arr[1] = "John"
arr[2] = "Tome"
arr[3] = "James"
arr[4] = "Adrew"
arr[5] = "Marter"

document.write(arr + "<br />")
arr.splice(3,1,"William")
document.write(arr)

運行結果: 

Geo,John,Tome,James,Adrew,Marter
Geo,John,Tome,William,Adrew,Marter

源碼

方法splice()在底層的源碼實現中,實際上對應着方法ArraySplice(),源碼位於v8/src/js/array.js中。二者的對應關係是在InstallFunctions中綁定的,具體看代碼:

// Set up non-enumerable functions of the Array.prototype object and
// set their names.
// Manipulate the length of some of the functions to meet
// expectations set by ECMA-262 or Mozilla.
// 方法名對應的綁定關係列表
utils.InstallFunctions(GlobalArray.prototype, DONT_ENUM, [
  "toString", getFunction("toString", ArrayToString),
  "toLocaleString", getFunction("toLocaleString", ArrayToLocaleString),
  "join", getFunction("join", ArrayJoin),
  "pop", getFunction("pop", ArrayPop),
  "push", getFunction("push", ArrayPush, 1),
  "reverse", getFunction("reverse", ArrayReverse),
  "shift", getFunction("shift", ArrayShift),
  "unshift", getFunction("unshift", ArrayUnshift, 1),
  "slice", getFunction("slice", ArraySlice, 2),
  "splice", getFunction("splice", ArraySplice, 2),
  "sort", getFunction("sort", ArraySort),
  "filter", getFunction("filter", ArrayFilter, 1),
  "forEach", getFunction("forEach", ArrayForEach, 1),
  "some", getFunction("some", ArraySome, 1),
  "every", getFunction("every", ArrayEvery, 1),
  "map", getFunction("map", ArrayMap, 1),
  "indexOf", getFunction("indexOf", null, 1),
  "lastIndexOf", getFunction("lastIndexOf", ArrayLastIndexOf, 1),
  "reduce", getFunction("reduce", ArrayReduce, 1),
  "reduceRight", getFunction("reduceRight", ArrayReduceRight, 1),
  "copyWithin", getFunction("copyWithin", ArrayCopyWithin, 2),
  "find", getFunction("find", ArrayFind, 1),
  "findIndex", getFunction("findIndex", ArrayFindIndex, 1),
  "fill", getFunction("fill", ArrayFill, 1),
  "includes", getFunction("includes", null, 1)
]);

其中,ArraySplice()方法的具體實現如下:

function ArraySplice(start, delete_count) {
  CHECK_OBJECT_COERCIBLE(this, "Array.prototype.splice");

  var num_arguments = arguments.length;
  var array = TO_OBJECT(this);
  var len = TO_LENGTH(array.length);
  var start_i = ComputeSpliceStartIndex(TO_INTEGER(start), len);
  var del_count = ComputeSpliceDeleteCount(delete_count, num_arguments, len,
                                           start_i);
  var deleted_elements = ArraySpeciesCreate(array, del_count);
  deleted_elements.length = del_count;
  var num_elements_to_add = num_arguments > 2 ? num_arguments - 2 : 0;

  if (del_count != num_elements_to_add && %object_is_sealed(array)) {
    throw %make_type_error(kArrayFunctionsOnSealed);
  } else if (del_count > 0 && %object_is_frozen(array)) {
    throw %make_type_error(kArrayFunctionsOnFrozen);
  }

  var changed_elements = del_count;
  // 如果刪除的元素個數和增加的元素個數不一致,則計算需要移動的元素位數
  if (num_elements_to_add != del_count) {
    // If the slice needs to do a actually move elements after the insertion
    // point, then include those in the estimate of changed elements.
    changed_elements += len - start_i - del_count;
  }
  if (UseSparseVariant(array, len, IS_ARRAY(array), changed_elements)) {
    %NormalizeElements(array);
    if (IS_ARRAY(deleted_elements)) %NormalizeElements(deleted_elements);
    SparseSlice(array, start_i, del_count, len, deleted_elements);
    SparseMove(array, start_i, del_count, len, num_elements_to_add);
  } else {
    SimpleSlice(array, start_i, del_count, len, deleted_elements);
    SimpleMove(array, start_i, del_count, len, num_elements_to_add);
  }

  // 從刪除元素的位置開始添加元素 
  var i = start_i;
  var arguments_index = 2;
  var arguments_length = arguments.length;
  while (arguments_index < arguments_length) {
    array[i++] = arguments[arguments_index++];
  }
  array.length = len - del_count + num_elements_to_add;

  // 返回刪除的元素
  return deleted_elements;
}

參考鏈接

http://www.ecma-international.org/ecma-262/5.1/#sec-15.4.4.12

https://github.com/v8/v8/blob/ad82a40509c5b5b4680d4299c8f08d6c6d31af3c/src/js/array.js

https://www.w3school.com.cn/jsref/jsref_splice.asp

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章