开始
JS的数组中有很多API,其中包括很多ES6新增的方法,每个API的的传参,返回值以及是否会修该原数组有很大不同,如果能从原理角度,并且依赖js实现该方法,就可以更加熟练它的使用。下面我们就按着MDN 上的介绍依次实现。
MDN数组链接:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array
数组方法
Array.from
概念
Array.from() 方法从一个类似数组或可迭代对象创建一个新的,浅拷贝的数组实例。
实现
思路:
- 数组的静态方法,所以定义
Array._from=function(xxx){}
- 数组,类数组对象,可迭代对象都实现
Symbol.iterator
,只有实现该方法,才能实现遍历,所以我们可以依赖该方法来实现对目标对象的遍历。
Array._from=function(target,fn){
let data=target;
if(typeof data[Symbol.iterator]!='function')
{
return [];
}
if(typeof fn!=='function')
{
fn=false;
}
// 必须实现迭代器
const it= data[Symbol.iterator](),res=[];
let end=false;
while (!end)
{
let {value,done}=it.next();
if(!done)
{
if(fn){
res.push(fn(value))
}
else{
res.push(value);
}
}
end=done;
}
return res
}
测试
let a='1111',b=10,c=new Set([1,2,3])
console.log(Object.getOwnPropertySymbols(a.__proto__)) //
console.log(Array._from(a))
console.log(Object.getOwnPropertySymbols(b.__proto__)) //[] 数字没有实现遍历器,所以返回空数组
console.log(Array._from(b)) //[]
console.log(Object.getOwnPropertySymbols(c.__proto__)) //[ Symbol(Symbol.toStringTag), Symbol(Symbol.iterator) ]
注意
从测试结果可以看出 是否可以被转成数组,关键取决于目标对象原型上实现是否实现了Symbol(Symbol.iterator)
Array.isArray()
作用
Array.isArray() 用于确定传递的值是否是一个 Array。
实现
思路
- 数组上的静态方法。定义 Array._isArray
- 我们依赖
Object.prototype.toString
检验是否是数组。
代码
Array._isArray=function (target) {
return Object.prototype.toString.call(target).slice(8,-1)==='Array'
}
测试
很简单没有多余可说的
console.log(Array._isArray([1])); //true
console.log(Array._isArray(1)); // false
Array.of
作用
Array.of() 方法创建一个具有可变数量参数的新数组实例,而不考虑参数的数量或类型。
注意:其实和Array 区别不大,就是单个参数有所不同
Array.of(6) //[6]
Array(6) [empty × 6]
思路
- 数组的静态方法
- 将argument(也是类数组对象)可以使用for遍历
实现
Array._of=function(){
console.log(arguments);//[Arguments] { '0': 1, '1': 2, '2': 3 }
let arr=[];
for(let item of arguments)
{
arr.push(item)
}
return arr;
}
测试
Array._of(1,2,3) //[1,2,3]
Array._of(1) //[1]
Array.prototype.concat()
concat() 方法用于合并两个或多个数组。此方法不会更改现有数组,而是返回一个新数组。
示例
console.log([].concat(1,2)); //[ 1, 2 ]
console.log([3].concat(1,[2])); //[ 3, 1, 2 ]
console.log([].concat(1,2,[3,[4]])); [ 1, 2, 3, [ 4 ] ]
console.log(Array.prototype.concat(1,2,[3,4])) // [1,2,3,4]
思路
- 数组原型上方法 需要 定义
Array.prototype._concat=function(){}
- 可以合并多个对象
- 合并对象如果是数组,会扁平化第一层。
- 返回一个新数组,不改变原数组
我们根据如下分析来逐步实现
实现方法
Array.prototype._concat=function () {
let target=this instanceof Array?this:[];
//将形参转为数组(slice 下一节我们会实现)
let args=Array.prototype.slice.call(arguments);
//生成一个新数组
let res=[];
while(target.length>0)
{
res.push(target.shift())
}
//对于需要合并对象 数组
while(args.length>0)
{
let value=args.shift();
//扁平化
if(value instanceof Array)
{
for(let item of value)
{
res.push(item);
}
}
//直接插入
else{
res.push(value);
}
}
return res;
}
测试
同样我们可以得到如下结果
console.log([]._concat(1,2)); //[ 1, 2 ]
console.log([3]._concat(1,[2])); //[ 3, 1, 2 ]
console.log([]._concat(1,2,[3,[4]])); //[ 1, 2, 3, [ 4 ] ]
Array.prototype.entries()
作用
entries() () 方法返回一个新的Array Iterator对象,该对象包含数组中每个索引的键/值对。
keys() 方法返回一个包含数组中每个索引键的Array Iterator对象。
values() 方法返回一个新的 Array Iterator 对象,该对象包含数组每个索引的值。
以上三个方法原理一样,我们在这实现entries() 方法。
思路
- 数组原型上已经实现
Symbol.iterator
遍历器方法,只需要获得它并执行就能得到
实现
Array.prototype._entries=function(){
let arr=[];
for(let i=0;i<this.length;i++)
{
arr.push([i,this[i]])
}
//新数组执行
return arr[Symbol.iterator]();
}
测试
也没啥可多说的
const array1 = ['a', 'b', 'c'];
const iterator1 = array1._entries();
console.log(iterator1.next().value);
// expected output: Array [0, "a"]
console.log(iterator1.next().value);
结语
先总结以上五个方法,以上方法总体来说还是相对比较简单的,下一继续根据MDN上的介绍和用法依次进行总结。
网友评论