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

开始

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

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,636评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,890评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,680评论 0 330
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,766评论 1 271
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,665评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,045评论 1 276
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,515评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,182评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,334评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,274评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,319评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,002评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,599评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,675评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,917评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,309评论 2 345
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,885评论 2 341