You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
为啥有问题?好好看报错!cannot read property Symbol(Symbol.iterator) 也就是说,如果你想创建一个可迭代对象,你需要让这个对象(类)拥有一个私有标识:Symbol.iterator 。确切地来说,Set 的构造器要求对象具有的这一私有的标识,本质上要求应该是一个“具有 next 方法、且每次 next 方法会返回一个具有 done 和 value 两个属性的对象”的方法,done 的值为布尔值、为 false 则可以继续执行 next 取下一个值。多说无益,show u my code :
varfoo={0 : 'zero',1 : 'one',2 : 'two',3 : 'three',length : 4};foo[Symbol.iterator]=function(){leti=0;letl=this.length;letthat=this;console.log('someone is using the iterator')return{next(){if(i<l){console.log('now:'+that[i]+',progress:'+i+'/'+l)return{done: false,value: that[i++]};}return{done: true};}};}newSet(foo);
为了学习 ES6 里面 Set、Map、WeakSet 和 WeakMap 的知识,懒癌晚期的我第一选择立刻翻阅阮一峰老师的 ES6入门 ,挑选里面的局部内容进行摘抄和理解。
Set
看到这句我们可以基本明白,Set 是 “无重复的值的数组 (Array) ”。
然后我们会发现,Set 居然没有 push 、shift 这类的方法吗?不是说是无重复值的数组吗?
原来,Set 的本质还是一个对象,它并不是数组。我们看一下 Set 的构造函数:
*可迭代对象
这里提到了可迭代对象,很多时候我们只记得可迭代对象一般是能够被
for( ... in ... ){}
进行遍历的对象/值。比较常见的可迭代对象:字符串、数组、对象。按照这种说法,那 Object 岂不是也可以被 Set 作为参数……个屁!并不能。凭啥?我们来看看在 MDN 中的真正的定义:
内置字符串对象,数组,类数组……这些才是在 JS 语言中真正的可迭代对象(说起来字符串本身也是一种类数组哦)。所以刚刚的测试报错,我们就用 DevTools 所理解的伪数组(有 length 属性、且有 splice 方法的对象)来骚操作一下 :
为啥有问题?好好看报错!
cannot read property Symbol(Symbol.iterator)
也就是说,如果你想创建一个可迭代对象,你需要让这个对象(类)拥有一个私有标识:Symbol.iterator 。确切地来说,Set 的构造器要求对象具有的这一私有的标识,本质上要求应该是一个“具有 next 方法、且每次 next 方法会返回一个具有 done 和 value 两个属性的对象”的方法,done 的值为布尔值、为 false 则可以继续执行 next 取下一个值。多说无益,show u my code :
输出结果如图:
![image.png](https://camo.githubusercontent.com/aa6ecdf07a4a8ecbf5863e4fa8ea54d4bb223d96c956fbaa5c395412824f2632/68747470733a2f2f63646e2e6e6c61726b2e636f6d2f79757175652f302f323031392f706e672f3233383634322f313535353735343439393134362d35653235653332372d613163642d343531302d393233622d3634663464373531666165322e706e6723616c69676e3d6c65667426646973706c61793d696e6c696e65266865696768743d313334266e616d653d696d6167652e706e67266f726967696e4865696768743d323534266f726967696e57696474683d3731382673697a653d3430333331267374617475733d646f6e652677696474683d333830)
关于迭代器的一些知识搜索来源于 David Tang 博客中的 《Iterables and Iterators in JavaScript》 ,原文干货很多,建议 Mark 。
![image.png](https://camo.githubusercontent.com/3cd0117cc4b156b8ff65419784edb7bde3514b82c139654ff9296e72f116b0d8/68747470733a2f2f63646e2e6e6c61726b2e636f6d2f79757175652f302f323031392f706e672f3233383634322f313535353735343733343430392d66646164653565362d303233652d346365632d396138622d3630633333393034373933612e706e6723616c69676e3d6c65667426646973706c61793d696e6c696e65266865696768743d323239266e616d653d696d6167652e706e67266f726967696e4865696768743d343238266f726967696e57696474683d3834322673697a653d3633373536267374617475733d646f6e652677696474683d343530)
按照这种思路,我们甚至可以写一些坑爹东西忽悠 Set 构造器:
就此打住,我们把重心转移回 Set 上。
刚刚我们看到 Set 可以理解为无序的、无重复子元素的数组,所以 Set 理所应当也具有一些和数组相似的方法:
理解到这里,用 Set 给一些存了基本类型数据的数组去重,就很好理解了。
Map
阮一峰老师在文中有一个特别好的总结,我们摘录下:
粗暴理解下,Map 是一个可以用 “任何值” 作为 **键名 **的 对象 。更严谨地说,不是“任何值”,而是“任何指针”。可以用阮一峰老师的例子说明:
最好玩的是,Map 和 Set 的构造器所传参数是一样的——无参数、或者可迭代对象。
只要基于数组理解 Set , 基于对象理解 Map ,其实他俩在意义和特性上是很好理解的,具体的一些方法和属性可以参考阮一峰老师 ES6入门 上的 这一章节 来具体学习。
WeakSet
顾名思义,WeakSet 是“弱 Set”——弱引用版本的 Set。光是知道这句话是不行的,很多同学在刚接触这个定义的时候会有这种猜想:
然后果不其然,我们会被 pia pia 打脸:
![image.png](https://camo.githubusercontent.com/f5f528a6338e5a6bd4929db679d706f6a8a6b6c8da4597fcbdec042898280750/68747470733a2f2f63646e2e6e6c61726b2e636f6d2f79757175652f302f323031392f706e672f3233383634322f313535353831393130313833312d36346231303339622d313832642d343266642d393239312d6234376638306335633065642e706e6723616c69676e3d6c65667426646973706c61793d696e6c696e65266865696768743d323039266e616d653d696d6167652e706e67266f726967696e4865696768743d323938266f726967696e57696474683d3338372673697a653d3334333330267374617475733d646f6e652677696474683d323731)
“说好的弱引用呢?”
甚至我们掏出 MDN 会发现一个特别神奇的事情:WeakSet 几乎不兼容各种主流浏览器,只有 Chrome 被标注支持了,甚至 Chrome 也要强调:只有开启实验性 JavaScript 才支持。所以 WeakSet 到底是何许码也?既然明码标价是弱引用,那怎么样才能触发它的这个特性,回收后让 WeakSet 中的相关内容消失?
既然已经走到了这里,我们就一口气把 JavaScript 浏览器端和 WeakSet 相关的内存管理、弱引用等知识都搞清楚。首先我们了解下 JavaScript 里有关变量回收的一些规则(参考文章):
所以我们再修改一下上方的代码。
但是结果却依然不行,如图:
![image.png](https://camo.githubusercontent.com/972a008cd5d099191f89f1af58855b5ac59561c9e6918b3ff1e332252bd441e1/68747470733a2f2f63646e2e6e6c61726b2e636f6d2f79757175652f302f323031392f706e672f3233383634322f313535353832373431383435342d34633863626163632d343765332d343935372d623363312d3937313131316361303030642e706e6723616c69676e3d6c65667426646973706c61793d696e6c696e65266865696768743d313832266e616d653d696d6167652e706e67266f726967696e4865696768743d313832266f726967696e57696474683d3237342673697a653d3230363832267374617475733d646f6e652677696474683d323734)
原来,JavaScript 语言中,内存的回收并不是在执行 delete 操作符断开引用后即时触发的,而是根据运行环境的不同、在不同的运行环境下根据不同浏览器的回收机制而异的。比如在 Chrome 中,我们可以在控制台里点击 CollectGarbage 按钮来进行内存回收:
在点击此按钮后,我们再打印上方的 ws 变量:
关于在不同浏览器环境下手动进行内存回收的具体异同,可参考:如何手动触发 JavaScript 垃圾回收行为?
每次都必须使用 delete 一个一个删除属性吗?并不,delete 的意义是“断开引用”,同样的,我们也可以用这种方式来进行清理:
这样我们就彻底搞清楚了:JavaScript 会在执行内存回收时,清除掉 被引用次数为0 的那部分内存;而 WeakSet 是只能储存对象的(或者说只能储存内存指针而非静态值)、并且它对对象的引用将不计入对象的引用次数,当清除对象属性、对应的内存被清理之后,WeakSet 中记录的内存地址上不再有内容,它将自动断开与这条引用的关联 —— 也正因如此,它所储存的内容会受到开发者对其他对象操作的被动影响,所以 WeakSet 在设计上就设计成了没有“长度”、“遍历”概念的特殊弱引用 Set 型。
这样的弱引用,用途上可以开一些脑洞,比如阮一峰老师的例子:
相比 WeakMap,它的应用能力不是特别强,或许这也是它目前没有被广泛支持的原因吧。
WeakMap
理解了迭代器、弱引用、内存回收,对 WeakMap 我们就可以很简单地去理解了:
WeakMap 是一个只能以 对象 作为键名的 Map,同时 WeakMap 上 每个键名对应的引用也是弱引用的。
也就是我们刚刚 WeakSet 的值的那种实验,在 WeakMap 的键名上是依然存在的。比如:
懂得很多道理,却依然过不好这一……呸!既然知道定义了就应该知道怎么用!我们先以阮一峰老师的例子 A 来看:
把 DOM 节点用作它的键名是一个常见场景,对应的可以做各种各样的骚操作。再看阮一峰老师的例子 B :
在这两个例子的基础上,我的理解是:WeakMap 非常擅长去配合 非常态的实例、节点、属性 一同使用,在那些内容被销毁时跟着一起被回收。很多时候我们不得不用一些变量来给这些东西做各种各样的辅助,比如 计数器、状态标识、临时值储存……在这种情况下,我们学习了 WeakMap ,就可以用 WeakMap 来做这个辅助的集中管理。
顺带一提, WeakMap 的浏览器支持性完爆 WeakSet ……
![image.png](https://camo.githubusercontent.com/bf3294864a587b25d97195d65e7908b720b22063e6b9302a16d92c19bb9220c7/68747470733a2f2f63646e2e6e6c61726b2e636f6d2f79757175652f302f323031392f706e672f3233383634322f313535353833303538333434342d31323162343837312d643362342d346336392d396134382d3339323234323734333635312e706e6723616c69676e3d6c65667426646973706c61793d696e6c696e65266865696768743d333235266e616d653d696d6167652e706e67266f726967696e4865696768743d393133266f726967696e57696474683d313134342673697a653d313531333431267374617475733d646f6e652677696474683d343037)
感悟
虽然最初只是想大概知道下这几个 ES6 新出的小老弟是干啥用的,不过顺便就把所有的相关知识都梳理了下。我们已经可以看到这些 ES6 的福利正在逐渐普及,和我一样是万年切图仔的同学们也要适当充实下自己在基础方面的知识,不要只知其然不知其所以然啦~
The text was updated successfully, but these errors were encountered: