📕 重学JavaScript:如何手写一个`push`高阶函数?

简介: `push` 高阶函数是一个非常常用的数组方法,可以让你用一种简单的方法来添加数组里的元素。

📕 重学JavaScript:如何手写一个push高阶函数?

嗨,大家好!这里是道长王jj~ 🎩🧙‍♂️

push 高阶函数是一个非常常用的数组方法,可以让你用一种简单的方法来添加数组里的元素。

push可以让你把一些新的元素放到数组的末尾,让数组变得更长。

比如,你可以用push来把5和6放到数组里,让它变成[1, 2, 3, 4, 5, 6]。😊

在ECMA中,也就是一群很聪明的人制定的一些规则中,他们已经给我们解释了push方法是怎么工作的。

他们用了一段伪代码,也就是一种类似于真正代码但是不完全一样的东西,来描述push方法的每一个步骤:

1. Let O be ? ToObject(this value).
2. Let len be ? LengthOfArrayLike(O).
3. Let argCount be the number of elements in items.
4. If len + argCount > 253 - 1, throw a TypeError exception.
5. For each element E of items, do
    a. Perform ? Set(O, ! ToString(𝔽(len)), E, true).
    b. Set len to len + 1.
6. Perform ? Set(O, "length", 𝔽(len), true).
7. Return 𝔽(len).

好的,根据这个原理,我们可以用JavaScript来实现我们的目标。😎

⭕ 解答一部分实现的关键逻辑

把调用push函数的值转换成一个对象(ToObject)。

保证 push 函数可以接受任何类型的值作为参数,比如字符串、数字、布尔等,不会因为用户传入的差异导致报错。

// 假设我们有一个数组arr
let arr = [1, 2, 3, 4];
// 把它转换成一个对象O
let O = Object(arr);

获取对象的长度(LengthOfArrayLike)

确定我们需要遍历对象中的多少个元素

// 获取对象O的所有属性名
let keys = Object.keys(O);
// 获取它们的个数,也就是对象O的长度len
let len = keys.length;

检查一下对象的长度加上新元素的个数是否超过了最大限制

保证我们传入的个数是有效的,不会超过Javascript能处理的范围

我们使用 typeof 运算符来判断

如果不是,我们就抛出一个类型错误

  if (len + argCount > 253 - 1) {
   
    throw new TypeError("Maximum array length exceeded");
  }

其他的都是口水话,很简单,这里我就不过多解释了,接下来直接上源码。

💌 完整代码解析如下:

// 定义一个push高级函数
function push(...items) {
   
  // 把数组变成一个对象
  let O = Object(this);
  // 把对象的长度记下来
  let len = Object.keys(O).length;
  // 把要添加的元素的个数记下来
  let argCount = items.length;
  // 检查一下对象的长度加上新元素的个数是否超过了最大限制,如果是,就报错
  if (len + argCount > 253 - 1) {
   
    throw new TypeError("Maximum array length exceeded");
  }
  // 对于每一个要添加的新元素,做以下事情
  for (let E of items) {
   
    // 把新元素放到对象里,并给它一个属性名叫做对象的长度
    O[len] = E;
    // 把对象的长度加1
    len++;
  }
  // 把对象的长度更新到对象里,并叫做"length"
  O.length = len;
  // 返回对象的长度
  return len;
}

这个方法其实没什么难点。

💨 我们试一下是否能实现效果

let arr = [1, 2, 3, 4];
let result = push.call(arr, 5, 6);
// 6
console.log(result);
// [1, 2, 3, 4, 5, 6]
console.log(arr);

✔ V8引擎中的map源码是怎么实现的呢?

我在这里直接粘贴给大家看看,大家自行对比一下:

// Appends the arguments to the end of the array and returns the new
// length of the array. See ECMA-262, section 15.4.4.7.
function ArrayPush() {
   
  CHECK_OBJECT_COERCIBLE(this, "Array.prototype.push");

  var array = TO_OBJECT(this);
  var n = TO_LENGTH(array.length);
  var m = arguments.length;

  // Subtract n from kMaxSafeInteger rather than testing m + n >
  // kMaxSafeInteger. n may already be kMaxSafeInteger. In that case adding
  // e.g., 1 would not be safe.
  if (m > kMaxSafeInteger - n) throw %make_type_error(kPushPastSafeLength, m, n);

  for (var i = 0; i < m; i++) {
   
    array[i+n] = arguments[i];
  }

  var new_length = n + m;
  array.length = new_length;
  return new_length;
}

📕 参考资料

V8数组部分源码第413行

ecma262草案


🎉 你觉得怎么样?这篇文章可以给你带来帮助吗?如果你有任何疑问或者想进一步讨论相关话题,请随时发表评论分享您的想法,让其他人从中受益。🚀✨

目录
相关文章
|
6月前
|
前端开发 JavaScript
前端基础 - JavaScript高级应用(高阶函数)
前端基础 - JavaScript高级应用(高阶函数)
32 0
|
9月前
|
存储 JavaScript 前端开发
js数组高阶函数——includes()方法
js数组高阶函数——includes()方法
192 0
|
22天前
|
JavaScript 安全 前端开发
高阶函数(js的问题)
高阶函数(js的问题)
|
4月前
|
JavaScript
【升级玩法】js用push、unshift、shift、pop或splice实现5张卡片(可以自由定义更多)轮播图效果banner、swiper
【升级玩法】js用push、unshift、shift、pop或splice实现5张卡片(可以自由定义更多)轮播图效果banner、swiper
|
8月前
|
JavaScript 索引
JS数组常用方法(超级详细,含理解) push、pop、unshift、shift、splice、slice、concat、join、revres、indexOf、sort、filter、map
JS数组常用方法(超级详细,含理解) push、pop、unshift、shift、splice、slice、concat、join、revres、indexOf、sort、filter、map
145 0
|
9月前
|
JavaScript 前端开发 数据格式
vue写法——使用js高阶函数实现多条件搜索功能
vue写法——使用js高阶函数实现多条件搜索功能
110 0
vue写法——使用js高阶函数实现多条件搜索功能
|
9月前
|
前端开发 JavaScript 数据可视化
React写法——使用js高阶函数实现多条件搜索功能
React写法——使用js高阶函数实现多条件搜索功能
|
9月前
|
JavaScript 索引
js数组高阶函数——map()方法
js数组高阶函数——map()方法
114 0
|
9月前
|
存储 SQL JavaScript
js数组高阶函数——filter()方法
js数组高阶函数——filter()方法
|
10月前
|
JavaScript 前端开发
📕 重学JavaScript:如何手写一个`reduce`高阶函数?
`reduce` 高阶函数是一个非常常用的数组方法,可以让你用一种简单的方法来处理数组里的元素。 数组就是一串有顺序的东西,比如[1, 2, 3, 4]就是一个数组,里面有四个数字。👌
111 0