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入门--阮一峰

有不当或者错误的地方请指正,谢谢~

相关推荐