深入了解Array.prototype.slice.call(arguments)

深入了解Array.prototype.slice.call(arguments)

  • 对于Array.prototype.slice.call(arguments),我网上一搜,大部分都只是讲解了作用
    “把类数组对象转为数组对象,而并没有分析其原理
  • 下面让我来谈谈我对它的理解

1.首先介绍它的两种写法

  • Array.prototype.slice.call(arguments) 或者 [].shift.call(arguments ) 这两种写法都能把 伪数组arguments转换成真正的数组
  • es6语法中新增了Array.from(),所以上述类型的对象可以Array.from(obj)就直接转化成数组
	//第一种调用call只改变this指向为 arguments
    function add() {
      console.log(arguments) // {0: 7, 1:8, 2:9, length: 2  其他....}
      var _args = Array.prototype.slice.call(arguments)
      console.log(_args)  //  [7,8,9]
    }
    add(7,8,9) 

	// 第二种调用call改变this指向为 arguments,并且传入start,end
    function add1() {
      console.log(arguments) // {0: 7, 1:8, 2:9, length: 2  其他....}
      var _args1 = Array.prototype.slice.call(arguments,0,1)  // this = rguments ,从第一位开始剪切,剪切一个
      console.log(_args1)  // [7]
    }
    add1(7,8,9) 
	

2.call()

  • call()不多介绍,想必大家也知道,它在这里只是起到改变slice()里面的this指向,使它指向arguments(不懂call,或忘记了的话,请到这里学习call

3.arr.slice()方法用法

  • 作用: 剪切数组,并返回一个新的数组,不会改变原来的数组
  • 语法: arr.slice(start,end)
  •    start : 必需。规定从何处开始选取。如果是负数,那么它规定从数组尾部开始算起的位置。
       也就是说,-1 指最后一个元素,-2 指倒数第二个元素,以此类推。
       
       end: 可选。规定从何处结束选取。该参数是数组片断结束处的数组下标。
       如果没有指定该参数,那么切分的数组包含从 start 到数组结束的所有元素。
       如果这个参数是负数,那么它规定的是从数组尾部开始算起的元素。
    
    当然,讲到这还是不能解释Array.prototype.slice.call(arguments)如何将arguments变成真正的数组,
    让我们接着看下面arr.slice()源码分析

4.arr.slice()源码分析

v8引擎中slice源码地址第587行

function ArraySlice(start, end) {
  // 对this进行检查,判断其是否可以具象化为对象变量,不行则抛出异常
  CHECK_OBJECT_COERCIBLE(this, "Array.prototype.slice");
  // this具象化为对象变量,也就是this指向的数组本身
  var array = TO_OBJECT(this);
  // length合法性处理, 它必须是一个有效范围内的整数。 转换数组长度
  var len = TO_LENGTH(array.length);
  // start转换为整数 start_i (从哪里开始剪切 => 开始值)
  var start_i = TO_INTEGER(start);
  // (剪切多少位=>结束值)  默认是array.length
  var end_i = len;
  // 原本 end_i = len 如果形参end不等于undefined, 则end_i = end
  if (!IS_UNDEFINED(end)) end_i = TO_INTEGER(end);
  // 如果传入的start为负数,则从尾部开始推算
  if (start_i < 0) { 
    start_i += len;
    // 绝对值大于len(数组长度) 则start_i赋值为0
    if (start_i < 0) start_i = 0;
  } else {
  	// start_i大于len(数组长度) 则start_i = len(数组长度)
    if (start_i > len) start_i = len;
  }
  // 以上总结 start_i为负数值从尾部开始推算,最小值是0,最大值是数组的长度.
  
  //   end_i(结束值)为负数,从尾部往前推算
  if (end_i < 0) {
    end_i += len;
    // end_i(结束值)最小值为0
    if (end_i < 0) end_i = 0;
  } else {
    // end_i(结束值)最大值为len(数组长度)
    if (end_i > len) end_i = len;
  }
  // 创建指定长度新数组result	             // MaxSimple(a,b) 取其中最大的值  		  			
  var result = ArraySpeciesCreate(array, MaxSimple(end_i - start_i, 0));
  // 返回空数组                       
  if (end_i < start_i) return result;
  // array是数组
  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 {
  // array不是数组
    SimpleSlice(array, start_i, end_i - start_i, len, result);
  }
  result.length = end_i - start_i;
  
  return result;
}

/*
* array 具体操作的非数组
* start_i 开始位置
* del_count  新数组esult.length
* len array.length
* deleted_elements  新数组result
*/
// 处理array不是数组(伪数组=>具有length属性)
function SimpleSlice(array, start_i, del_count, len, deleted_elements) {
    for (var i = 0; i < del_count; i++) {
        var index = start_i + i;
        if (index in array) {
            var current = array[index];
           // CreateDataProperty接受参数O(一个对象)、P(一个属性键)和V(一个ECMAScript语言值)
            %CreateDataProperty(deleted_elements, i, current);
        }
    }
}

5.总结

  • Array.prototype.slice.call(arguments)
    1.首先调用call(arguments),使得slice()方法中的this指向了arguments,
    2.然后通过4.arr.slice()源码分析,我们就能知道slice()是如何将伪数组arguments转为真正的数组.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值