6

es6中提供将其他数据转化为数组的快捷API

 3 years ago
source link: https://segmentfault.com/a/1190000007391121
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

Array.from

Array.from方法主要用于将Array-Like Obj(包括DOM对象document.querySeletorAll(...))和iterable对象转化为数组。和下面说的spread操作符相比,它可以直接将Array-Like obj进行转化,而不需要这个类数组对象是iterable的。

    function add() {
        let arr = [].slice.apply(arguments);
    }
    
    function add() {
        let arr = Array.from(arguments);
    }
    
    --------
    
    //通过这个方法,将`Array-Like Obj`直接转化为了Array.因此可以使用Array提供的方法
    var lis = Array.from(document.querySelectorAll('li'));
    lis.forEach(function(dom, index) {
        // do something
    });

此外,Array.from还接收第二个参数,和Array.prototype.map方法类似.

    function foo() {
        let args = Array.from(arguments, item => item + 1);
        console.log(args);
    }
    
    foo(1, 2, 3);    // 2 3 4

可以利用Array.from来返回字符串的长度,因为在js里面,大于uFFFF的Unicode字符长度是算为2个的。

    //这里是因为String类型的数据是iterable的,所以可以被Array.from转化为数组
    function countLen(str) {
        return Array.from(str).length;
    }

...args (rest参数)

rest参数主要是在定义函数的时候,用以获取函数多余的函数,这样在函数内部即可不使用arguments对象.因为rest参数是一个数组,因此可以直接利用Array提供的相应的API。

    比如一个求和的函数:
    
    以前的写法:
    function add() {
        [].reduce.call(arguments, function(x, y) {
            return x + y;
        });
    }
    
    es6:
    
    function add(...args) {
        args.reduce((x, y) => x + y);
    }

还可以使用rest参数搭配解构赋值使用:

    function foo(...args) {
        let [x = 0, y = 2] = args;
        //....
    }

在使用箭头函数的时候:

    function foo(...args1) {
        var obj = {
            add: () => {
                console.log(arguments);
            }
        }
        obj.add(1, 2, 3);
    }
    
    foo(4, 5, 6);   //最后输出 [4, 5, 6]
    

这里因为箭头函数没有自身的this,它内部的this事实上是由所在的作用域提供的。因此arguments对象也是所在作用域提供的。所以会输出[4, 5, 6]

这里如果要正确获取obj.add(1, 2, 3)提供的参数,可以使用rest参数:

    function foo(...args1) {
        var obj = {
            add: (...args2) => {
                console.log(args2);
            }
        }
        obj.add(1, 2, 3);
    }
    
    foo(4, 5, 6);    //最后输出  [1, 2, 3]

spread操作符

spread操作符用以将一个iterable(部署了[Symbol.Iterator]接口)的value转化为用逗号分隔的参数序列。

哪些数据结构部署了[Symbol.Iterator]的接口呢:

  • Array

  • 部署了[Symbol.Iterator]接口的Array-like obj(arguments)

  • Dom data Structures

  • String

对象字面量:

    var obj = {
        name: 'xl',
        age: 20
    }
    
    console.log(...obj);

是没有部署[Symbol.Iterator]接口的,因此使用spread操作符时会报错:

Uncaught TypeError: (var)[Symbol.iterator] is not a function(…)

同时,普通的Array-likeObj:

    var obj = {
        0: 'x',
        1: 'l',
        length: 2
    }

同样使用spread操作符时会报错。如果将这个Array-likeObj转化为Array,则需要手动在这个obj上配置[Symbol.iterator]接口:

    var obj = {
        *[Symbol.iterator]() {
            yield 'x';
            yield 'l'
        }
    }
    
    console.log(...obj);    //  x l

或者换用其他的API:

    方式1: let arr1 = Array.from(obj);
    
    方式2: let arr1 = [].slice.apply(obj);

像之前计算一组数当中最大的数:

    Math.max.apply(null, [1, 2, 3]);
    
    --->>> Math.max(...[1, 2, 3]);      // 3

此外,spread操作符还能将部署了[Symbol.Iterator]接口的类数组对象转为用逗号分隔的参数序列:

    var li = document.querySeletorAll('li');
    
    [...li];   //转化为数组后就可以利用数组提供的API进行其他的操作

Symbol.Iterator

上面多次提到了iterable或者是部署了[Symbol.iterable]方法的value,事实上它们说的都是同一个意思,一个话去概括的话就是: iterable的数据结构提供了统一的接口供外部去获取自身的元素。它所提供的这个接口方法名称就是[Symbol.iterator].

上文已经提到了哪些数据结构部署了[Symbol.Iterator]的接口。

哪些方法会调用[Symbol.Iterator]接口呢:

    let [a, b] = [1, 2];
  • for...of循环

    for(let value of [1, 2]) {
    
    }
  • spread操作符

    [...document.querySelectorAll('li')]
  • Promise.all()/Promise.race()

    Promise.all(iterableOverPromises).then(···);
    Promise.race(iterableOverPromises).then(···);
  • yield*

    yield* anIterable

关于iterableiterator单独用一篇文章来写吧。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK