Tag Archives: Array.prototype.slice.call(arguments)

How to Use Array.prototype.slice.call(arguments)

In the Es5 standard, we often need to convert the arguments object into a real array

1 // You can write it like this
2 var arr = Array.prototype.slice.call(arguments)
3 
4 // You can write it like this
5 var arr = [].slice.call(arguments)
6 
7 // If you are not afraid of trouble, you can also write like this
8 var arr = [].__proto__.slice.call(arguments)

The above three writing methods are equivalent

1 // When you understand the prototype chain, you know
2 Array.prototype === [].__proto__  // true
3  
4 // [].slice calls the slice method in the prototype object of the instance[]
5 [].slice === [].__proto__.slice  // true

Array.prototype.slice.call (arguments) originally called slice by array.prototype, but call (arguments) changed the object calling slice method to arguments. You can imagine that

Array.prototype.slice.call(arguments) ~ arguments.slice()

Array.prototype.slice.call(arguments, [begin[, end]]) ~ arguments.slice([begin [, end]])

We may think that the arguments prototype object is object. Prototype, and there is no slice method. Where does slice method come from

This is because call (arguments) not only changes the direction of this, but also makes the arguments object inherit the slice method in array. Prototype

The following is the source code of array. Prototype. Slice(): 587 lines of GitHub address

function ArraySlice(start, end) {
  CHECK_OBJECT_COERCIBLE(this, "Array.prototype.slice");

  var array = TO_OBJECT(this);
  var len = TO_LENGTH(array.length);
  var start_i = TO_INTEGER(start);
  var end_i = len;

  if (!IS_UNDEFINED(end)) end_i = TO_INTEGER(end);

  if (start_i < 0) {
    start_i += len;
    if (start_i < 0) start_i = 0;
  } else {
    if (start_i > len) start_i = len;
  }

  if (end_i < 0) {
    end_i += len;
    if (end_i < 0) end_i = 0;
  } else {
    if (end_i > len) end_i = len;
  }

  var result = ArraySpeciesCreate(array, MaxSimple(end_i - start_i, 0));

  if (end_i < start_i) return result;

  if (UseSparseVariant(array, len, IS_ARRAY(array), end_i - start_i)) {
    %NormalizeElements(array);
    if (IS_ARRAY(result)) %NormalizeElements(result);
    SparseSlice(array, start_i, end_i - start_i, len, result);
  } else {
    SimpleSlice(array, start_i, end_i - start_i, len, result);
  }

  result.length = end_i - start_i;

  return result;
}

Arguments can be converted to array objects because

We can see that the member properties of the arguments object are similar to arrays and have the length property. Is it so that similar objects can call slice?Let’s have a test

1 var obj = {
2     0: 'foo',
3     1: 'bar',
4     2: 'arg',
5     length: 3
6 }
7 console.log(Array.prototype.slice.call(obj))
8 // ["foo", "bar", "arg"]

This is OK

*PS: ES6 syntax adds array. From (), so the above types of objects can be directly converted into arrays by array. From (obj)