📕 重学JavaScript:如何手写一个pop
高阶函数?
嗨,大家好!这里是道长王jj
~ 🎩🧙♂️
pop
高阶函数是一个非常常用的数组方法,可以让你用一种简单的方法来删除数组里的元素。
pop
可以让你把数组的最后一个元素拿出来,并返回它。
比如,你可以用pop
来拿出数组里的4,并返回它,让数组变成[1, 2, 3]。😊
在ECMA中,也就是一群很聪明的人制定的一些规则中,他们已经给我们解释了pop
方法是怎么工作的。
他们用了一段伪代码,也就是一种类似于真正代码但是不完全一样的东西,来描述pop
方法的每一个步骤:
1. Let O be ? ToObject(this value).
2. Let len be ? LengthOfArrayLike(O).
3. If len = 0, then
a. Perform ? Set(O, "length", +0𝔽, true).
b. Return undefined.
4. Else,
a. Assert: len > 0.
b. Let newLen be 𝔽(len - 1).
c. Let index be ! ToString(newLen).
d. Let element be ? Get(O, index).
e. Perform ? DeletePropertyOrThrow(O, index).
f. Perform ? Set(O, "length", newLen, true).
g. Return element.
好的,根据这个原理,我们可以用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;
删除对象里对应的值
使用delete的时候,原数组的length不会变更,需要同步更改。
delete O[index];
O.length--;
其他的都是口水话,很简单,这里我就不过多解释了,接下来直接上源码。
💌 完整代码解析如下:
function pop() {
// 把数组变成一个对象
let O = Object(this);
// 把对象的长度记下来
let len = Object.keys(O).length;
// 检查一下对象是否为空,也就是长度是否为0
if (len === 0) {
// 如果是,就做以下事情
// 把对象的长度更新为0,并叫做"length"
O.length = 0;
// 返回undefined
return undefined;
}
// 如果对象不为空,就做以下事情
else {
// 把对象的长度减1,并叫做newLen
let newLen = len - 1;
// 把newLen转换成字符串,并叫做index
let index = String(newLen);
// 把对象里index这个属性对应的值赋给一个变量叫做element
let element = O[index];
// 删除对象里index这个属性及其对应的值
delete O[index];
// 把对象的长度更新为newLen,并叫做"length"
O.length = newLen;
// 返回element
return element;
}
}
这个方法其实没什么难点。
💨 我们试一下是否能实现效果
let arr = [1, 2, 3, 4];
let result = arr.pop();
// 4
console.log(result);
// [1, 2, 3]
console.log(arr);
✔ V8引擎中的map源码是怎么实现的呢?
我在这里直接粘贴给大家看看,大家自行对比一下:
// Removes the last element from the array and returns it. See
// ECMA-262, section 15.4.4.6.
function ArrayPop() {
CHECK_OBJECT_COERCIBLE(this, "Array.prototype.pop");
var array = TO_OBJECT(this);
var n = TO_LENGTH(array.length);
if (n == 0) {
array.length = n;
return;
}
n--;
var value = array[n];
%DeleteProperty_Strict(array, n);
array.length = n;
return value;
}
📕 参考资料
🎉 你觉得怎么样?这篇文章可以给你带来帮助吗?如果你有任何疑问或者想进一步讨论相关话题,请随时发表评论分享您的想法,让其他人从中受益。🚀✨