进阶练习:手写JavaScript数组多个方法的底层实现

进阶练习:手写JavaScript数组多个方法的底层实现

先了解一下push方法的底层实现:
下面是ECMA的英文相关解释
When the push method is called with zero or more arguments
the following
steps are taken:
1.Let O be ? To0bject(this value).2.Let len be ? LengthOfArrayLike(O).
3.Let argCount be the number of elements in items.
4. If len + argCount > 2453- 1, throw a TypeError exception.5. For each element E of items, do
a.Perform ? Set(0,!ToString(F(len)), E, true).b. Set len to len + 1.
5. Perform ? Set(0, “length”, F(len), true).7.Return F(len).
下面我们将上述的英文转化成代码

Array.prototype.push = function(...items){
let O = Object(this); // ecma中提到的先转换为对象let len = this. length >>>0;
let argCount = items.length >>> O;//2453-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;}

你会发现有些变量再进行无符号位移,你可以自己研究一下
pop的底层实现
下面是ECMA的英文注解:
When the pop method is called, the following steps are taken:1. Let O be ? ToObject(this value).
6. Let len be ? LengthOfArrayLike(O).3. If len = 0, then
Perform ? Set(0, “length”,+OF, true).Return undefined.
7. Else,
Assert: len > 0.
Let newLen be F(len - 1).
Let index be ! ToString(newLen).Let element be ? Get(0, index).
Perform ? DeletePropertyOrThrow(0, index).Perform ? Set(0, “length”, newLen, true).Return element.
下面我们将上述内容转化为代码实现:

Array. prototype.pop = function(){let O = Object(this);
let len = this.length >>> 0;if (len === 0){
0.length = 0;return undefined;}
len --,
let value = O[len];delete O[len];0.length = len;return value;}

map方法的底层实现
下面依然是ECMA的标准解释
When the map method is called with one or two arguments, the following steps are taken:1.Let O be ? To0bject(this value).
2.Let len be ? LengthOfArrayLike(O).
3.If lsCallable(callbackfn) is false, throw a TypeError exception.4. Let A be ? ArraySpeciesCreate(0, len).
8. Let k be 0.
9. Repeat, while k< len,
a. Let Pk be ! ToString(F(k)).
b. Let kPresent be ? HasProperty(O, Pk).c. If kPresent is true, then
Let kValue be ? Get(0, Pk).
Let mappedValue be ? Call(callbackfn, thisArg, kValue,F(k), O 》).Perform ? CreateDataPropertyOrThrow(A, Pk, mappedValue).d. Set k to k+1.
7.Return A.
下面我们将上述语言转化为代码:

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(callbacktn) != ".ODJect runction] ) ithrow new TypeError(callbackfn + ' is not a function')
}
let O = Object(this);let T = thisArg;
let len = 0.length >>>0;let A = new Array(len);
for(let k = 0; k<len; k++){if(k in O){
if(k in O){
let kValue = O[k];/依次传入this,当前项,当前索引,整个数组
let mappedValue = callbackfn.call(T, KValue,k, O);A[k] = mappedValue;
}
}
return A;}

需要注意一点:遍历类型的方法最后返回的都是一个新数组并不改变原有数组的值,切记
reduce的底层方法实现:
When the reduce method is called with one ortwo arguments, the followingsteps are taken:
1.Let O be ? ToObject(this value).
2.Let len be ? LengthOfArrayLike(O).
10. If lsCallable(callbackfn) is false, throw a TypeError exception.
11. If len =0 and initialValue is not present, throw a TypeError exception.5.Let k be 0.
6.Let accumulator be undefined.
7.If initialValue is present, thenSet accumulator to initialValue.
8. Else,
Let kPresent be false.
Repeat, while kPresent is false and k< len,Let Pk be ! ToString(F(k)).
Set kPresent to ? HasProperty(O, Pk).lf kPresent is true, then
Set accumulator to ? Get(O, Pk).Set k to k+1.
If kPresent is false, throw a TypeError exception.9.Repeat, while k<len,
Let Pk be ! ToString(F(k)).
Let kPresent be ? HasProperty(O, Pk).lf kPresent is true, then
将其转换为代码:

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 = 0.length >>>0;let k=0;
let accumulator = initialValue; // reduce方法第二个参数作为累加器的初始值if (accumulator === undefined){//初始值不传的处理
for(; k<len ; k++){
if(k in O){
accumulator = O[k];k++;
break;}
}
throw new Error('Each element of the array is empty');}
for(;k<len; k++){
if(k in o){
//注意reduce的核心累加器
accumulator = callbackfn.call(undefined,accumulator,o[k],o);
}
}
return accumulator;

默认初始值不传的特殊处理
累计器以及callbackfn的处理逻辑
上述文章如果有问题或者想问问题或者想交流技术或者想和作者闲聊可以+QQ:2029788643

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值