ES6 -- 数据结构Set、Map,Module语法及加载实现
前言:ES6学习总结
好吧ES8都出来了,我还在学ES6,没事的,我皮厚~
1、Set
Set是ES6新加的一种数据结构,类似数组, Set本身是个构造函数,用来生成Set数据结构,new Set() 有个特点**成员值唯一,无重复的值(敲黑板)**,这一特性在数组去重的时候非常好用。
1.Set构造函数接受数组作为参数
2.Array.from方法可以将 Set 结构转为数组。
// 去除数组的重复成员 const arr1 = [1,3,5,3,1] const set = new Set(arr1); [...set] // [1, 3, 5] ...是ES6展开运算符 const arr2 = Array.from(set); //arr1:[1,3,5,3,1] //arr2:[1,3,5]
属性:
Set.prototype.constructor:构造函数,默认就是Set函数。 Set.prototype.size:返回Set实例的成员总数。
方法:
操作方法
add(value):添加某个值,返回Set结构本身。 delete(value):删除某个值,返回一个布尔值,表示删除是否成功。 has(value):返回一个布尔值,表示该值是否为Set的成员。 clear():清除所有成员,没有返回值。
遍历方法
keys():返回键名的遍历器 values():返回键值的遍历器 entries():返回键值对的遍历器 forEach():使用回调函数遍历每个成员
2、Map
类似于对象,是键值对的集合,但是‘键’不限字符串,可以是‘值-值’对应,Map构造函数可以接受双元素数组的数据结构作为参数,比如array、Set。 1.size--返回Map成员总数 2.set(key,value) set方法设置键名key对应的键值为value,然后返回整个 Map 结构。如果key已经有值,则键值会被更新,否则就新生成该键。 3.get(key) get方法读取key对应的键值,如果找不到key,返回undefined。 4.has(key) has方法返回一个布尔值,表示某个键是否在当前 Map 对象之中。 5.delete(key) delete方法删除某个键,返回true。如果删除失败,返回false。 6.clear()--clear方法清除所有成员,没有返回值.
遍历方法
keys():返回键名的遍历器。 values():返回键值的遍历器。 entries():返回所有成员的遍历器。 forEach():遍历 Map 的所有成员。
与其他数据结构相互转换
Map <==> 数组 Map <==> 对象 Map <==> JSON 具体操作方法见API
3.Module语法
Module即模块,其实模块化跟前后端分离出发点是一样的,解耦,提高开发效率,代码易维护及二次开发
两个命令:import 和 export 输入和输出
export命令可以输出模块,供其他模块调用,
// a.js export var name1 = 'zhangsan'; const name2 = 'lisi' //b.js import {a} from 'a.js'; console.log(name1,name2); //zhangsan/undefiled
除了变量还可以输出函数、类(class)
输出的时候可以用as取别名方便区分使用
import命令可以引入其他模块,调用其他模块输出的变量、函数、类,
引入的时候同样可以as取别名方便区分使用
import { schoolName as name1 } from './a';
另外:import命令具有提升效果,会提升到整个模块的头部,首先执行。但是,在头部统一import是个好习惯,
import是静态执行,所以不能使用表达式和变量,不允许运行时改变
例子:{
import { 'a' + 'b' } from 'a';//报错
}
模块整体加载
import * as obj from './a';
用(*)号指定一个对象,再用as取别名,所有输出值都在这个对象上面
export default命令
export default命令为模块指定默认输出;
这句话的意思就是,默认输出一个default变量,这个变量包含你写的变量方法等等,使用的时候不需要记住export的变量名和函数名等,import之后就可以直接使用了。
打个比方:
//a.js export const A; const B; export const C; //c.js export default{ const D,E,F; AAA(){ ... } } //b.js import {a} from './a'; import c from './c' console.log(D,E,F); //true AAA();//true
注意下import a、c 的区别,export default后再引入就不需要{}号了
不想暴露给其他模块的方法可以写在export default外面;
export 与 import 复合写法
export { aa, bb } from './a'; 等同于先引入aa、bb再输出aa、bb
接口改名,整体输出也可以用复合写法
// 接口改名 export { foo as myFoo } from 'my_module'; // 整体输出 export * from 'my_module';
模块的继承
看到继承就想起刚才的export 和 import的复合使用,先引入再输出不就继承了吗,
//b.js export * from './a';
但是,export * 命令会忽略a.js模块的default方法,所以必须改名后输出
跨模块常量
这块没什么好说的,直接搬代码
// constants.js 模块 export const A = 1; export const B = 3; export const C = 4; // test1.js 模块 import * as constants from './constants'; console.log(constants.A); // 1 console.log(constants.B); // 3 // test2.js 模块 import {A, B} from './constants'; console.log(A); // 1 console.log(B); // 3
如果常量较多,创建一个专门放常量的目录,里面存储各种放常量的文件
import()
前面说过,import是静态加载,但是require是运行时加载模块,所以引入import()方法来进行运行时加载,接受一个参数,就是指定要加载的模块的路径,支持变量、计算、表达式等等,
相较require,import()是异步,require是同步。
import()可以在需要时加载,不会像import那样首先执行,满足按需加载、条件加载、动态路径加载。
4.Module 的加载实现
浏览器加载
<!-- 页面内嵌的脚本 --> <script type="application/javascript"> // module code </script> <!-- 外部脚本 --> <script type="application/javascript" src="path/to/myModule.js"> </script>
浏览器通过script标签加载JavaScript
<script src="path/to/myModule.js" defer></script>//渲染完执行 <script src="path/to/myModule.js" async></script>//下载完立即执行,
设置type="module"浏览器会知道这是一个ES6模块,等同于打开script的defer属性。当然,也可以设置成anysc属性,
模块中引入其他模块不可省略.js后缀,vue可以因为它做了处理。
模块中,顶层的this关键字不是指向window而是undefined,
CommonJS 模块的顶层this指向当前模块,
相同模块,加载多次只执行一次,
Node加载
Node有自己的CommonJs模块,并且跟ES6模块不兼容,所以分开采用各自的加载方法,一个模块只要有一行import或export就会被Node认为是ES6模块,否则CommonJs模块,如果不输出任何接口又希望被Node认为是ES6 模块可以加一句
export {}
这不是输出空对象,而是不输接口;
用import命令加载CommonJs模块,会把CommonJs的module.exports转化为export default输出,
require命令加载 ES6 模块
采用require命令加载 ES6 模块时,ES6 模块的所有输出接口,会成为输入对象的属性。
//a.js dexport default{ const A = 1; Const B = 2; } //b.js const cc = require('./a.js'); console(cc.defaule);
循环加载
当两个模块或两个以上模块互相依赖,模块就要相互引入加载,这种强耦合关系,容易导致递归加载,尽量避免
CommonJS 模块的循环加载;CommonJs是运行时加载,
//a.js const A = 1; var b = require('./b.js'); const AA = 11; console.log(C,CC); // 2 22 //b.js const C = 2; var a = require('./a.js'); cons CC = 22; console.log(A,AA);// 1 undefined
假设先执行a.js
AA之所以没有值,是因为当b.js执行到var a = require('./a.js');的时候,a.js只输出一个A,而不是输出全部,
ES6 模块的循环加载
// a.js import {bar} from './b.js'; console.log('a.js'); console.log(bar); export let foo = 'foo'; // b.js import {foo} from './a.js'; console.log('b.js'); console.log(foo); export let bar = 'bar'; //输出 //b.js //undefined //a.js //bar
假先执行a.js,
第一行就会进入到b.js而不会往下,到b.js的时候第一行是引入a.js,进入a.js不往下,等a.js加载完成,再从b.js第二行开始执行。
参考自ES6入门--阮一峰
有不当或者错误的地方请指正,谢谢~