ES6 的 for..of 和 Generator,从伪数组 jQuery 对象提及

pseudo

英 [‘sju:dəʊ] 美 [‘su:doʊ]
adj.假的,虚假的
n.[口]冒充的人,伪君子

pseudo-array

英 [s’ju:dəʊər’eɪ] 美 [s’ju:dəʊər’eɪ]
[计] 伪数组

jQuery 对象是伪数组

两个现实

不论之前晓得不晓得,最少马上会晓得

  1. jQuery 对象是一个伪数组。

    var $obj = jQuery();
    Array.isArray($obj);    // false
  2. jQuery.fnjQuery.prototype 的简写

    jQuery.fn === jQuery.prototype;    // true   

提出问题

既然 jQuery 对象是伪数组,那 ES6 的 for…of 想用在 jQuery 对象上就不会那末顺遂。毕竟 jQuery 还没有按 ES6 重写。

那末,想用 for..of 遍历 jQuery 对象中的 DOM 援用,就本身完成吧——这得从 iterable 和 iterator 最先。

The for…of statement creates a loop Iterating over iterable objects (including Array, Map, Set, arguments object and so on), invoking a custom iteration hook with statements to be executed for the value of each distinct property.

援用自:for…of statement | MDN

iterable(可迭代对象) 和 iterator(迭代器)

不以礼貌,不成方圆

为了使某个对象成为可迭代对象象,它必需完成 @@iterator 要领,也就是说,它得有一个 key 是 Symbol.iterator 的属性。说人话,就是必需得完成这么个东东:

jQuery.fn[Symbol.iterator] = ....

而这个所谓的 @@iterator 要领,返回的是一个迭代器。迭代器这活也不是随意谁都醒目的,它必需得有一个 next() 要领,而这个 next() 要领每次挪用,都返回下一个迭代对象。

固然迭代对象也是有规范的,它必需是这么个构造:

{
    done: "(boolean),true 示意迭代完成,false 示意另有下一个",
    value: "这个才是正主,for...of 迭代出来的值"
}

注重 done 这个小坑,别的语言中通常是用 hasNext() 或许 hasMore() 之类的来推断是不是有下一个值,而 javascript 是用 done 来推断,它们的逻辑意义恰好相反,所以万万注重不要给错了值。

注:Symbol 是 ES6 中引入的新的键范例。之前的键范例只能是字符串,而在 ES6 中,有两种了。关于 Symbol,能够参阅 【探秘ES6】系列专栏(八):JS的第七种基础范例SymbolsSymbol – JavaScript | MDN

完成

晓得了礼貌,完成起来就好办了

jQuery.fn[Symbol.iterator] = function() {
    return (function(_this) {
        var index = 0;
        return {
            next: function() {
                return {
                    done: index >= _this.length,
                    value: _this[index++]
                };
            }
        };
    })(this);
};

测试

for (var dom in $("div")) {
    console.log(dom);
}

准确实行,经由历程……话虽云云,代码写起来好累。所以,实在应该用 Generator……

Generator

ES6 的又一新特征,Generator 对象(天生器对象),几乎就是为迭代而生的。每一个天生器对象都相符上面提到的 iterable 和 iterator 两个礼貌。换句话说,天生器对象既是一个可迭代对象,又是一个迭代器,而它作为可迭代对象的时刻,返回的迭代器就是它本身。

然则天生器对象并非 new 出来的,而是经由历程 generator function(天生器函数)天生的;天生器函数得本身写,又不能 new Generator(),那末这个天生器对象从哪里来呢?固然是天生器函数天生的,而且这会用到新语法,以及新的症结字 yield

generator function(天生器函数)和 yield

天生器函数的定义与一般函数略有差别,形式上的区分是,它在 function 症结字后加了一个 * 号,就像如许:

function *aGenerator() { ... }

天生器函数在内容上的区分就是,它的内容实在并非它本身的内容,而是形貌了它发生天生器对象的行动。

有点乱,来捋一捋:

  • 天生器函数返回一个天生器对象
  • 天生器对象是一个迭代器
  • 天生器对象也是一个可迭代对象,每次迭代返回本身(这句临时疏忽)
  • 迭代器有一个 next() 要领用来返回迭代值(以及推断是不是完成迭代)

捋清晰了,来讲天生器函数的内容——实在就是干上面末了一条形貌的事变:形貌每次迭代返回的值,以及是不是完成迭代。这是与一般 function 完整差别的语法,它是怎样做到的呢?平空说起来太费劲,先上代码

function *aGenerator() {
    yield 1;
    yield 2;
    yield 3;
}

每次 yield,就相当于一次经由历程 next() 返回值,也就上面提到的迭代对象的 value 属性。那末 done 属性怎样肯定呢?假如从天生器函数返回,就 done 了。这有两种状况,一种是天然实行完一切语法,函数完毕返回;另一种是在函数体中挪用 return 返回。

新问题:眼看例中 3 个 yield 语句排在一同,不是“啪啪啪”一会儿就搞完了?末了就 next() 出来一个 3 了事?

非也,yield 返回值与 return 差别。yield 反回值(也就是 next())以后会将代码停息在那个位置,等下一次 next() 的时刻,继承实行,到下一个 yield 再停息……云云直到显现或藏匿的 return

革新的 jQuery.fn[Symbol.iterator]

jQuery.fn[Symbol.iterator] = function*() {
    for (var i = 0; i < this.length; i++) {
        yield this[i];
    }
};

比上一个完成简朴了不少吧,然则你认为这是最简朴的么……

奇妙的完成

更简朴的完成

除了能够用 yield 返回值以外,还能够用 yield *返回可迭代对象。这时候,控制权会临时交给这个可迭代对象,由它代替完成 next(),直到 done,再由当前天生器函数中的下一个 yield 接办继承。抽象一点的明白——这个历程有点像树型构造的深度遍历。

由于原生数组也是可迭代对象,所以能够取个巧

jQuery.fn[Symbol.iterator] = function*() {
    yield *[].slice.call(this);
};

最简朴的完成

上面说了一通,用了 N 种要领,无非是解说 ES6 的新特征罢了。要为 jQuery 完成 for…of 遍历,最简朴的要领实际上是拿来主义:

jQuery.fn[Symbol.iterator] = [][Symbol.iterator];

末了的提示

jQuery 对象是一个伪数组,它的每一个元素都是一个 DOM(或原对象)而不是被封装的 jQuery 对象,所以,用 for..of 遍历的时刻,和用 jQuery.fn.each() 遍历一样,假如想继承在每一个元素上运用 jQuery 的特征,就要记得用 jQuery() 包装。

// for...of
for (var dom in $("span")) {
   var $span = $(dom);
}

// jQuey.fn.each
$("span").each(function() {
    var $span = $(this);
});

慎重道歉

实在,我不小心又骗了人人。jQuery 压根没有完成 for...of 的必要,纵然没有 ES6,用 for...in 遍历 jQuery 对象也是一件很悲催的事变,不信你尝尝。

jQuery 的遍历,相对应该用 jQuery.fn.each()

然则,看在我要以此为例来讲 ES6 的几样新特征的份上,谅解我吧!^_^!

参考

    原文作者:边城
    原文地址: https://segmentfault.com/a/1190000003704450
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞