用法
对于基本类型的包装对象来说,调用该方法会返回对应的基本类型值,但对于数组一般会直接返回数组本身
const arr = [1,2,3] arr.valueOf() === arr
实现
Array.prototype.myValueOf = function(){ return this }
用法
将数组中的每个元素转为字符串并用规定好的分隔符进行连接:
undefined
,而 undefined
和 null
会进一步被转化为空字符串。[1,2,3].join() // "1,2,3" 缺省是逗号作为连接符 [1,2,3].join('.') // "1.2.3" [{},{},{}].join('**') // "[object Object]**[object Object]**[object Object]"
实现
Array.prototype.myJoin = function(connector = ','){ let arr = this let str = '' for(x of arr){ x = typeof(x) === 'undefined' || x === null ? "" : x str += x.toString() + connector } return str.slice(0,str.length - connector.length) } // 或者 Array.prototype.myJoin = function(connector = ','){ let arr = this let len = arr.length let str = '' for(let i = 0;i < len;i++){ arr[i] = typeof(arr[i]) === 'undefined' || arr[i] === null ? "" : arr[i] // 如果是最后一个元素,则不加连接符(后缀符) str += arr[i].toString + (i === len - 1 ? '' : connector) } return str }
用法
toString 可以看作是 join 的一种特殊情况,即传入的分隔符是逗号,其它的都一样(包括对 undefined
、null
和 empty 元素的处理)
[1,2,3].toString() // "1,2,3" [{a:1},{b:2}].toString() // "[obejct Object],[object Object]"
实现
Array.prototype.myToString = function(){ let arr = this let str = "" for(x of arr){ x = typeof(x) === 'undefined' || x === null ? "" : x str += `${x.toString()},` } return str.slice(0,str.length - 1) }
用法
concat 可以用于合并数组
[Symbol.isConcatSpreadable]=true
,此时会取出这个对象的每一项(除了 length
)放入新数组[Symbol.isConcatSpreadable]=false
实现
Array.prototype.myConcat = function(...args){ let arr = this let res = [] let k = 0 const isArrayLike = obj => { if( typeof o === 'object' && isFinite(o.length) && o.length >= 0 && o.length === Math.floor(o.length) && o.length < 4294967296) return true else return false } for(let el of arr){ res[k++] = el } for(let el of args){ // 如果是数组且没有禁止展开 if(Array.isArray(el) && el[Symbol.isConcatSpreadable] != false){ for(let _el of el){ res[k++] = _el } } else { // 如果是类数组且允许展开 if(isArrayLike(el) && el[Symbol.isConcatSpreadable]){ for(let key in el){ // 把除了 length 之外的键值都放入新数组中 if(key !== 'length'){ res[k++] = el[key] } } } else { res[k++] = y } } } return res }
PS:这里检测类数组对象的方式可能不太严谨,且没有考虑 empty 元素的情况
用法
at 是一个比较新的方法,目前浏览器还没有实现:
相比 arr[2]
,这个方法的优势在哪里呢?优势在于可以很方便地访问那些数组末尾的元素,比如现在要访问 const arr = [1,2,3,4]
的倒数第二个元素,不再需要使用 arr[arr.length - 2]
,只需要 arr.at(-2)
。
const arr = [1,2,3,4] arr.at(2) // 3 arr.at(-1) // 4
实现
Array.prototype.myAt = function(searchIndex){ let arr = this let len = arr.length let searchIndex = searchIndex >= 0 ? searchIndex : Math.abs(searchIndex) < len ? searchIndex + len : Infinity return arr[searchIndex] }
用法
const arr = ['a','b','c','d','a','e'] arr.indexOf('b') // 从前往后查找'b',返回它的索引1 arr,indexOf('b',2) // 从索引2开始,从前往后查找'b',找不到,返回 -1 arr.lastIndexOf('a') // 从后往前查找'a',返回它的索引4 arr.lastIndexOf('a',2) // 从索引2开始,从后往前查找'a',返回它的索引0 arr.includes('c') // 数组存在'c',返回 true arr.includes('c',3) // 从索引3开始,数组不存在'c',返回 false arr.includes('c',300) // 超出数组长度,返回 false arr.includes('c',-2) // 负值=>负值+数组长度=>4,从索引4开始查找,返回 false arr.includes('c',-100) // 负值=>负值+数组长度=>-94,从头开始查找,返回 true
实现
Array.prototype.myIndexOf = function(target,start = 0){ let arr = this let len = arr.length let _start = start >= 0 ? start : Math.abs(start)<= len ? len + start : 0 for(;_start < len;_start++){ if(arr[_start] === target){ return _start } } return -1 }
用法
lastIndexOf 和 indexOf 相比,有些地方是反过来的:
const arr = [1,2,3,2,5] arr.lastIndexof(2) // 3
实现
Array.prototype.myLastIndexOf = function(target,start){ let arr = this let len = arr.length start = start || arr[arr.length - 1] let _start = start < 0 ? len + start : start >= len ? arr.length - 1 : start for(;_start > 0;_start--){ if(arr[_start] === target){ return _start } } return -1 }
用法
inlcudes 和 indexOf 类似,但是返回的是布尔值。
为什么有了 indexOf
还要引入 inlcudes
?一是因为返回布尔值,语义更加清晰;二是因为 includes
内部使用的是类似 Object.is
的比较方式,而非 indexOf 所使用的 ===
,所以可以准确判断 NaN。
[1,NaN].indexOf(NaN) // -1 [1,NaN],includes(NaN) // true // 然而,inlcudes 仍然无法准确判断±0,会认为两者相等 [1,+0].includes(-0) // true [1,0].includes(+0) // true
实现
Array.prototype.myIncludes = function(target,start = 0){ let arr = this let len = arr.length let _start = start >=0 ? start : Math.abs(start) <= len ? start + len : 0 function isSame(x,y){ return x === y || typeof(x)=='number'&&typeof(y)=='number'&&isNaN(x)&&isNaN(y) // return x === y || x!=x && y!= y // return x === y || Number.isNaN(x) && Number.isNaN(y) } for(;_start < len;_start++){ if(isSame(arr[_start],target)){ return true } } return false }
这里判断 NaN 的方式很多,一种是直接利用最准确的 Number.isNaN
,一种是使用 isNaN
,但要保证参数是数字,还有一种是利用 NaN 自身的特性,即“自己不等于自己”。
用法
slice 用于产生数组切片:
begin
和 end
,表示开始位置和结束位置;可以只接受一个参数 begin
,表示开始位置;可以不接受任何参数,则缺省开始位置为第一个元素,结束位置为最后一个元素begin
可以是正数或者负数:
end
可以是正数或者负数:
begin
可能大于 end
,此时就直接返回一个空数组const arr = [1,2,3,4,5] arr.slice(1) // [2,3,4,5] arr.slice(1,4) // [2,3,4] arr.slice(-4,-1) // [2,3,4] 负值 => 数组长度加负值 arr.slice(4,1) // [] 反向索引,返回空数组
实现
// 通过默认参数值,为 begin 和 end 设置缺省值 Array.prototype.mySlice = function(begin = 0,end = this.length){ let arr = this let len = arr.length let res = [] let k = 0 begin = begin >= 0 ? begin : Math.abs(begin) <= len ? begin + len : 0 end = end < 0 ? end + len : Math.min(end,len) for(;begin < end;begin++){ res[k++] = arr[begin] } return res }
用法
用于数组扁平化(数组降维):
Infinity
可以直接将数组转化为一维数组flat
的实现可以参考数组扁平化的方法,但它实现起来需要更加灵活,可以传参控制降维次数[1,[2,3],[[4,5],6]].flat() // [1,2,3,[4,5],6] [1,[2,3],[[4,5],6]].flat(2) // [1,2,3,4,5,6]
实现
1)reduce + 递归
Array.prototype.myFlat = function(times = 1){ let arr = this // 如果参数无法转化为数字,或小于等于0,则直接将原数组返回 if(!Number(times) || Number(times) <= 0){ return arr } return arr.reduce((acc,cur) => { return acc.concat(Array.isArray(cur) ? cur.myFlat(times - 1) : cur) },[]) }
2)forEach + 递归
Array.prototype.myFlat = function(times = 1){ let arr = this let res = [] if(!Number(times) || Number(times) <= 0){ return arr } arr.forEach(el => { res.concat(Array.isArray(el) ? el.myFlat(times - 1) : el) }) return res }
3)for 循环 + in 检查 + 递归
Array.prototype.myFlat = function(times = 1){ let arr = this let res = [] if(!Number(times) || Number(times) <= 0){ return arr } for(let i = 0;i < arr.length;i++){ if(i in arr){ if(Array.isArray(arr[i])){ res = [...res,...arr[i].myFlat(times - 1)] } else { res = [...res,arr[i]] } } } return res }