美文网首页
JS 中数组常用方法以及它的原理实现(一)

JS 中数组常用方法以及它的原理实现(一)

作者: 泰然自若_750f | 来源:发表于2020-07-08 21:40 被阅读0次

    开始

    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上的介绍和用法依次进行总结。

    掘金地址:https://juejin.im/user/5efd45a1f265da22f511c7f3/posts

    相关文章

      网友评论

          本文标题:JS 中数组常用方法以及它的原理实现(一)

          本文链接:https://www.haomeiwen.com/subject/rowhcktx.html