JS核心原理 - 模块二 - JS数组多个方法的底层实现

本文深入探讨了JavaScript数组的push、pop、map和reduce四个方法的底层实现逻辑,包括它们的关键步骤、异常处理和核心思想。通过分析源码,展示了如何在数组中添加、删除、映射和累加元素,帮助理解这些常用方法的工作原理。
摘要由CSDN通过智能技术生成

JS核心原理

模块二 深入数组篇

JS数组多个方法的底层实现

思考:
	1、reduce 方法里面的参数都是什么作用?
	2、push 和 pop 的底层逻辑是什么样的呢?
push 方法的底层实现
Array.prototype.push = function(...items) {

  let O = Object(this);  // ecma 中提到的先转换为对象

  let len = this.length >>> 0;

  let argCount = items.length >>> 0;

  // 2 ^ 53 - 1 为JS能表示的最大正整数

  if (len + argCount > 2 ** 53 - 1) {

    throw new TypeError("The number of array is over the max value")

  }

  for(let i = 0; i < argCount; i++) {

    O[len + i] = items[i];

  }

  let newLength = len + argCount;

  O.length = newLength;

  return newLength;

}

从上面的代码可以看出,关键点就在于给数组本身循环添加新的元素 item,然后调整数组的长度 length 为最新的长度,即可完成 push 的底层实现。
其中关于长度的部分需要做无符号位移,无符号位移在很多源码中你都会看到。关于为什么一些变量要进行无符号位移,你可以自己研究一下,比如在 Stack Overflow 中有一些高票的回答,这里就不占用篇幅了。下面我们再看来一下 pop 的实现。
pop 方法的底层实现
Array.prototype.pop = function() {

  let O = Object(this);

  let len = this.length >>> 0;

  if (len === 0) {

    O.length = 0;

    return undefined;

  }

  len --;

  let value = O[len];

  delete O[len];

  O.length = len;

  return value;

}

其核心思路还是在于删掉数组自身的最后一个元素,index 就是数组的 len 长度,然后更新最新的长度,最后返回的元素的值,即可达到想要的效果。另外就是在当长度为 0 的时候,如果执行 pop 操作,返回的是 undefined,需要做一下特殊处理。
map 方法的底层实现
Array.prototype.map = function(callbackFn, thisArg) {

  if (this === null || this === undefined) {

    throw new TypeError("Cannot read property 'map' of null");

  }

  if (Object.prototype.toString.call(callbackfn) != "[object Function]") {

    throw new TypeError(callbackfn + ' is not a function')

  }

  let O = Object(this);

  let T = thisArg;



  let len = O.length >>> 0;

  let A = new Array(len);

  for(let k = 0; k < len; k++) {

    if (k in O) {

      let kValue = O[k];

      // 依次传入this, 当前项,当前索引,整个数组

      let mappedValue = callbackfn.call(T, KValue, k, O);

      A[k] = mappedValue;

    }

  }

  return A;

}

有了上面实现 push 和 pop 的基础思路,map 的实现也不会太难了,基本就是再多加一些判断,循环遍历实现 map 的思路,将处理过后的 mappedValue 赋给一个新定义的数组 A,最后返回这个新数组 A,并不改变原数组的值。
reduce 方法的底层实现
Array.prototype.reduce  = function(callbackfn, initialValue) {

  // 异常处理,和 map 类似

  if (this === null || this === undefined) {

    throw new TypeError("Cannot read property 'reduce' of null");

  }

  // 处理回调类型异常

  if (Object.prototype.toString.call(callbackfn) != "[object Function]") {

    throw new TypeError(callbackfn + ' is not a function')

  }

  let O = Object(this);

  let len = O.length >>> 0;

  let k = 0;

  let accumulator = initialValue;  // reduce方法第二个参数作为累加器的初始值

  if (accumulator === undefined) {  

      throw new Error('Each element of the array is empty');

      // 初始值不传的处理

    for(; k < len ; k++) {

      if (k in O) {

        accumulator = O[k];

        k++;

        break;

      }

    }

  }

  for(;k < len; k++) {

    if (k in O) {

      // 注意 reduce 的核心累加器

      accumulator = callbackfn.call(undefined, accumulator, O[k], O);

    }

  }

  return accumulator;

}

根据上面的代码及注释,有几个关键点你需要重点关注:
	1、初始值默认值不传的特殊处理;
	2、累加器以及 callbackfn 的处理逻辑。
https://github.com/v8/v8/blob/98d735069d0937f367852ed968a33210ceb527c2/src/js/array.js

pop:	#L394
push:	#L414
map:	#L1036
slice:	#L586
filter:	#L1024
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

不甜的糖果

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值