JS中从Array.slice()与Array.splice()的底层实现原理分析区别

来源:互联网 发布:单片机如何烧程序 编辑:程序博客网 时间:2024/06/07 16:59

1.Array.prototype.slice()
slice() 方法返回一个从开始到结束(不包括结束)选择的数组的一部分浅拷贝到一个新数组对像,原始数组不会改变。

arrayObject.slice(start,end)
  • start (可选,如果start不写则从0开始)从该索引处开始提取原数组中的元素。
    如果该参数为负数,则表示从原数组中的倒数第几个元素开始提取,slice(-2)表示提取原数组的倒数第二个元素到最后一个元素(包含最后一个元素)。
  • end(可选)在该索引处结束提取原数组元素(从0开始)。slice会提取原数组中索引从 begin 到 end 的所有元素(包含begin,但不包含end)。
    *1.如果该参数为负数, 则它表示在原数组中的倒数第几个元素结束抽取。 slice(-2,-1)表示抽取了原数组中的倒数第二个元素到最后一个元素(不包含最后一个元素,也就是只有倒数第二个元素)。
    2.如果 end 被省略,则slice 会一直提取到原数组末尾。
    3.如果 end 大于数组长度,slice 也会一直提取到原数组末尾。*
    原理:
    (应该都能看懂)
// This will work for genuine arrays, array-like objects,     // NamedNodeMap (attributes, entities, notations),    // NodeList (e.g., getElementsByTagName), HTMLCollection (e.g., childNodes),    // and will not fail on other DOM objects (as do DOM elements in IE < 9)    Array.prototype.slice = function(begin, end) {      // IE < 9 gets unhappy with an undefined end argument      end = (typeof end !== 'undefined') ? end : this.length;      // For native Array objects, we use the native slice function      if (Object.prototype.toString.call(this) === '[object Array]'){        return _slice.call(this, begin, end);       }      // For array like object we handle it ourselves.      var i, cloned = [],        size, len = this.length;      // Handle negative value for "begin"      var start = begin || 0;      start = (start >= 0) ? start : Math.max(0, len + start);      // Handle negative value for "end"      var upTo = (typeof end == 'number') ? Math.min(end, len) : len;      if (end < 0) {        upTo = len + end;      }      // Actual expected size of the slice      size = upTo - start;      if (size > 0) {        cloned = new Array(size);        if (this.charAt) {          for (i = 0; i < size; i++) {            cloned[i] = this.charAt(start + i);          }        } else {          for (i = 0; i < size; i++) {            cloned[i] = this[start + i];          }        }      }      return cloned;    };

还可以查看V8源码第587行:直达

2.Array.prototype.splice()
splice()方法通过删除现有元素和/或添加新元素来更改一个数组的内容。
原型:Array.prototype.splice (start, deleteCount, item1, item2, … )

  • start
    指定修改的开始位置(从0计数)。如果超出了数组的长度,则从数组末尾开始添加内容;如果是负值,则表示从数组末位开始的第几位(从1计数)。
  • deleteCount (可选)
    整数,表示要移除的数组元素的个数。如果 deleteCount 是 0,则不移除元素。这种情况下,至少应添加一个新元素。如果 deleteCount 大于start 之后的元素的总数,则从 start 后面的元素都将被删除(含第 start 位)。
  • item1, item2, …(可选)
    要添加进数组的元素,从start 位置开始。如果不指定,则 splice() 将只删除数组元素。
    源码:
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);  }  // Insert the arguments into the resulting array in  // place of the deleted elements.  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 the deleted elements.  return deleted_elements;}

还可以查看V8源码第660行:直达
或者开发文档:ECMA5.1文档


请注意
1.splice() 方法会直接对数组进行修改。slice() 不对数组进行修改,原数组不会改变。
2.splice() 返回值为被操作的值。slice() 以新的字符串返回被提取的部分。
3.
[14, 3, 77].slice(1, 2) // [3]
[14, 3, 77].splice(1, 2) // [3, 77]

4.splice先执行删除操作,删除指定个数的元素,然后再插入elements(元素或数组),他的每次删除都涉及大量元素的重新排列,而在插入元素时引入队列来管理。所以splice()的效率不高

原创粉丝点击