Array.prototype.slice()

slice()方法法返回一个从开始到结束(不包括结束)选择的数组的一部分浅拷贝到一个新数组对象。

此方法不修改原数组,返回一个新数组。

注意:slice的复制是浅复制。

begin

起始索引,从这里开始提取数组中的元素。

如果该参数为负数,则表示从原数组中的倒数第几个元素开始提取,slice(-2)表示提取原数组中的倒数第二个元素到最后一个元素(包含最后一个元素)。
如果省略 begin,则 slice 从索引 0 开始。

end

结束索引,提取到这里结束,不包括结束索引的元素。

如果该参数为负数, 则它表示在原数组中的倒数第几个元素结束抽取。

如果 end 被省略,则slice 会一直提取到原数组末尾。
如果 end 大于数组长度,slice 也会一直提取到原数组末尾。

slice()方法返回含有提取元素的新数组。

var fruits = ['Banana', 'Orange', 'Lemon', 'Apple', 'Mango'];
var citrus = fruits.slice(1, 3);

// fruits contains ['Banana', 'Orange', 'Lemon', 'Apple', 'Mango']
// citrus contains ['Orange','Lemon']

在下例中, slice从myCar中创建了一个新数组newCar.两个数组都包含了一个myHonda对象的引用. 当myHonda的color属性改变为purple, 则两个数组中的对应元素都会随之改变.

// 使用slice方法从myCar中创建一个newCar.
var myHonda = { color: 'red', wheels: 4, engine: { cylinders: 4, size: 2.2 } };
var myCar = [myHonda, 2, "cherry condition", "purchased 1997"];
var newCar = myCar.slice(0, 2);

// 输出myCar, newCar,以及各自的myHonda对象引用的color属性.
console.log('myCar = ' + JSON.stringify(myCar));
console.log('newCar = ' + JSON.stringify(newCar));
console.log('myCar[0].color = ' + JSON.stringify(myCar[0].color));
console.log('newCar[0].color = ' + JSON.stringify(newCar[0].color));

// 改变myHonda对象的color属性.
myHonda.color = 'purple';
console.log('The new color of my Honda is ' + myHonda.color);

//输出myCar, newCar中各自的myHonda对象引用的color属性.
console.log('myCar[0].color = ' + myCar[0].color);
console.log('newCar[0].color = ' + newCar[0].color);

类数组Array-like对象

slice 方法可以用来将一个类数组(Array-like)对象/集合转换成一个新数组。你只需将该方法绑定到这个对象上。 一个函数中的 arguments 就是一个类数组对象的例子。

function list() {
  return Array.prototype.slice.call(arguments);
}

var list1 = list(1, 2, 3); // [1, 2, 3]

除了使用 Array.prototype.slice.call(arguments),你也可以简单的使用 [].slice.call(arguments) 来代替。另外,你可以使用 bind 来简化该过程。

var unboundSlice = Array.prototype.slice;
var slice = Function.prototype.call.bind(unboundSlice);

function list() {
  return slice(arguments);
}

var list1 = list(1, 2, 3); // [1, 2, 3]

跨浏览器转换DOM对象为数组

根据规范,使用 Array.prototype.slice 转换宿主对象(如 DOM 对象)时不必遵循 Mozilla 的默认行为,即可以转化任何符合条件的伪数组宿主对象为数组,IE < 9 没有遵循,而 IE9 + 遵循这个行为,但是稍加改造可以使其在跨浏览器使用时更可靠。只要其他现代浏览器继续支持该行为,目前 IE  9+、FireFox、Chrome、Safari 以及 Opera 都支持,开发者在使用下面代码时遍历 DOM 时就不会被该方法的字面意义误导,即 IE < 9 不能转化 DOM Collections。开发者可以安全地根据语义知道该方法的实际上的标准行为。(下面的代码还修正了 IE 中 slice() 方法第二个参数不允许为显式的 null/undefined 值的问题,其他现代浏览器,包括IE9+都允许)。

/**
 * Shim for "fixing" IE's lack of support (IE < 9) for applying slice
 * on host objects like NamedNodeMap, NodeList, and HTMLCollection
 * (technically, since host objects have been implementation-dependent,
 * at least before ES2015, IE hasn't needed to work this way).
 * Also works on strings, fixes IE < 9 to allow an explicit undefined
 * for the 2nd argument (as in Firefox), and prevents errors when
 * called on other DOM objects.
 */
(function () {
  'use strict';
  var _slice = Array.prototype.slice;

  try {
    // Can't be used with DOM elements in IE < 9
    _slice.call(document.documentElement);//尝试直接转换DOM元素为一个数组,IE9以下会报错走catch语句
  } catch (e) { // Fails in IE < 9
    // 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;//处理end未定义问题

      // For native Array objects, we use the native slice function
      if (Object.prototype.toString.call(this) === '[object Array]'){//判断this类型如果是Array对象,直接执行slice
        return _slice.call(this, begin, end); 
      }

      // For array like object we handle it ourselves.
      //其他的Array-like对象就自己处理
      var i, cloned = [],
        size, len = this.length;

      // Handle negative value for "begin"
      var start = begin || 0;//处理start为undefined的情况
      start = (start >= 0) ? start : Math.max(0, len + start);//处理start为负数情况

      // Handle negative value for "end"
      var upTo = (typeof end == 'number') ? Math.min(end, len) : len;//处理end是无效的参数的情况
      if (end < 0) {
        upTo = len + end;//end是负数的情况
      }

      // Actual expected size of the slice
      size = upTo - start;//最终需要slice的元素个数

      if (size > 0) {
        cloned = new Array(size);//cloned初始化为长度为size的数组
        if (this.charAt) {//如果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;
    };
  }
}());

 

posted @ 2018-06-28 14:48  hahazexia  阅读(334)  评论(0)    收藏  举报