手写数组方法
map
V8源码
Array.prototype.map = function(callbackFn, thisArg) { // 处理数组类型异常 if (this === null || this === undefined) { throw new TypeError("Cannot read property 'map' of null or undefined"); } // 处理回调类型异常 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; }
注意点:
- length >>> 0, 字面意思是指"右移 0 位",但实际上是把前面的空位用0填充,这里的作用是保证len为数字且为整数;
-
循环中使用 in 来进行原型链查找。同时,如果没有找到就不处理,能有效处理稀疏数组的情况。
如果用 hasOwnProperty 是有问题的,它只能找私有属性;
reduce
V8源码
Array.prototype.reduce = function(callbackfn, initialValue) { // 处理数组类型异常 if (this === null || this === undefined) { throw new TypeError("Cannot read property 'reduce' of null or undefined"); } // 处理回调类型异常 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; 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) { accumulator = callbackfn.call(undefined, accumulator, O[k], O); } } return accumulator; }
filter
Array.prototype.filter = function(callbackfn, thisArg) { // 处理数组类型异常 if (this === null || this === undefined) { throw new TypeError("Cannot read property 'filter' of null or undefined"); } // 处理回调类型异常 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 resLen = 0; let res = []; for(let i = 0; i < len; i++) { if (i in O) { let element = O[i]; if (callbackfn.call(thisArg, O[i], i, O)) { res[resLen++] = element; } } } return res; }
push
Array.prototype.push = function(...items) { let O = Object(this); 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 restricted!") } for(let i = 0; i < argCount; i++) { O[len + i] = items[i]; } let newLength = len + argCount; O.length = newLength; return newLength; }
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; }