美文网首页码农
js中伪数组转真数组

js中伪数组转真数组

作者: 潜水的旱鸭子 | 来源:发表于2019-10-14 15:22 被阅读0次

    一、什么是真数组(数组)

    所谓真数组,其实可以直接称为:数组。
    当一个对象具有以下特点时,可以称为数组:

    • 可以按照索引的方式,存储多个数组
    • 具有length属性,表示数组内数据的长度(个数)
    • 对象的原型属性__proto__,指向Array类,且可以使用Array的原型对象prototype身上的属性和方法,如:push,pop等。如图1:
    图1:真数组

    二、什么是伪数组

    所谓伪数组,当一个对象具有以下特点:

    • 具有length(长度)属性;
    • 可以使用索引对数据进行操作;
    • 但是不能使用数组的方法,如push,pop等。如图2:
    图2:伪数组

    注意:
    1.伪数组一般不会直接创建,而是通过一些js操作得到,如:document.getElementsByName()等;
    2.因为伪数组具有长度和索引,所以可以使用循环语句遍历;
    3.并不是能使用部分数组的方法,就是称为真数组;如图3:

    图3:依然是伪数组

    4.有些情况下,并不是将伪数组的原型__proto__属性设置为Array的原型对象prototype,就可以使用数组的方法。如图4:

    图4:还是伪数组

    三、如何将伪数组转成真数组

    如果在一些情况下,js给我们返回的是伪数组,但是我们想使用真数组的方法对之进行操作,那么此时就需要将伪数组转成真数组之后,才能继续使用。

    接下来我们根据伪数组和真数组的区别和特点,对伪数组做一下改造,将伪数组转成真数组,以完成后续操作。

    方法1:遍历:创建一个空数组,循环遍历伪数组,将遍历出的数据逐一放在空数组中

    var ali = document.getElementsByTagName('li');
    console.log(ali);       // [li, li, li, li]
    // ali.push("hello");      // TypeError: ali.push is not a function
    
    var arr = [];           // 先创建空数组
    for(var i=0;i<ali.length;i++){  // 循环遍历伪数组
        arr[i] = ali[i];    // 取出伪数组的数据,逐个放在真数组中
    }
    
    arr.push("hello");
    console.log(arr);       // [li, li, li, li, "hello"]
    

    方法2:使用slice方法:利用Array原型对象的slice方法,配合apply,将slice中的this指向伪数组

    var ali = document.getElementsByTagName('li');
    console.log(ali);       // [li, li, li, li]
    // ali.push("hello");      // TypeError: ali.push is not a function
    
    var arr = Array.prototype.slice.apply(ali);
    
    arr.push("hello");
    console.log(arr);       // [li, li, li, li, "hello"]
    

    方法3:利用ES6提供的Array的from方法

    var ali = document.getElementsByTagName('li');
    console.log(ali);       // [li, li, li, li]
    // ali.push("hello");      // TypeError: ali.push is not a function
    
    var arr = Array.from(ali);
    
    arr.push("hello");
    console.log(arr);       // [li, li, li, li, "hello"]
    

    方法4:利用ES6提供的展开运算符(...)

    var ali = document.getElementsByTagName('li');
    console.log(ali);       // [li, li, li, li]
    // ali.push("hello");      // TypeError: ali.push is not a function
    
    var arr = [...ali];
    
    arr.push("hello");
    console.log(arr);       // [li, li, li, li, "hello"]
    

    方法5:利用原型的复制:将伪数组的proto复制为Array的prototype。但是这种方法有局限性

    • 手动创建具有索引和长度的对象,作为伪数组
    var obj = {
        0:"a",
        1:"b",
        2:"c",
        length:3
    }
    console.log(obj);       // {0: "a", 1: "b", 2: "c", length: 3}
    // obj.push();          // TypeError: obj.push is not a function
    
    obj.__proto__ = Array.prototype;
    
    console.log(obj);       // ["a", "b", "c"]
    obj.push("hello");
    console.log(obj);       // ["a", "b", "c", "hello"]
    
    • arguments也适用
    function fn(){
        var arg = arguments;
        console.log(arg);       // ["a", "b", ...]
        // arg.push("hello");   // TypeError: arg.push is not a function
    
        arg.__proto__ = Array.prototype;
    
        arg.push("hello");
        console.log(arg);       // ["a", "b", "hello", ...]
    }
    fn("a","b");
    
    • 选择器返回的元素集合不适用,因为就算将元素集合的原型改成了数组原型(如图5),但元素集合本身是只读的,依然不能修改
    var ali = document.getElementsByTagName('li');
    console.log(ali);            // [li, li, li, li]
    // ali.push("hello");        // TypeError: ali.push is not a function
    
    ali.__proto__ = Array.prototype;
    
    // ali.push("hello");        // Index property setter is not supported
    
    图5

    但是不是意味着,没有修改到原数组的方法就可以使用呢(注意图5,没有length属性)

    ali.forEach(val => {
        console.log(val);
    });
    
    // 会发现浏览器没执行,原因是此时ali缺少length或length为0
    console.log(ali.length);    // 0
    

    需要提前获取ali的length,在修改原型之后再手动设置

    var ali = document.getElementsByTagName('li');
    console.log(ali);            // [li, li, li, li]
    // ali.push("hello");        // TypeError: ali.push is not a function
    
    var len = ali.length;        // 获取初始length
    ali.__proto__ = Array.prototype;
    ali.length = len;            // 设置给修改原型之后的数组对象
    
    // ali.push("hello");        // Index property setter is not supported
    ali.forEach(val => {
        console.log(val);        // 遍历打印数组中的值
    });
    console.log(ali.length);     // 4
    

    小提示:选择器返回的元素数组,使用复制原型方法,还需要手动设置length属性,且不能使用会改变原数组的方法。


    以上。
    关于伪数组转真数组的方法或技巧,后期继续补充...
    文中如果纰漏,错误,不合理,描述不清晰,不准确等问题,欢迎大家留言指正...

    相关文章

      网友评论

        本文标题:js中伪数组转真数组

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