1、let 与 const
1.1 let
1.1.1 作用
与var类似,声明一个变量
1.1.2 特点
-
声明的变量只在代码块内有效
{ let a = 10; var b = 1; } console.log(a) // ReferenceError: a is not defined. console.log(b) // 1
-
不允许重复声明
{ let a = 10; var a = 1; } console.log(a) //SyntaxError: Identifier 'a' has already been declared
-
不存在变量提升
// var 的情况 console.log(foo); // 输出undefined var foo = 2; // let 的情况 console.log(bar); // 报错ReferenceError let bar = 2;
-
暂时性死区
- 使用let命令声明变量之前,该变量都是不可用的。这在语法上,称为“暂时性死区”(temporal dead zone,简称 TDZ)。
if (true) { // TDZ开始 tmp = 'abc'; // ReferenceError console.log(tmp); // ReferenceError let tmp; // TDZ结束 console.log(tmp); // undefined tmp = 123; console.log(tmp); // 123 }
1.1.3 应用
循环遍历加监听
闭包方法输出索引
<button>按钮1</button>
<button>按钮2</button>
<button>按钮3</button>
<script>
var btns = document.querySelectorAll("button");
for (var i = 0; i < btns.length; i++) {
(function(i) {
btns[i].onclick = function() {
alert(i)
}
})(i);
}
</script>
let 方法
<button>按钮1</button>
<button>按钮2</button>
<button>按钮3</button>
<script>
var btns = document.querySelectorAll("button");
for (let i = 0; i < btns.length; i++) {
btns[i].onclick = function() {
alert(i)
}
}
</script>
1.2 const
1.2.1 作用
声明一个常量,一旦声明就不能修改
1.2.2 特点
- 声明后值不能修改
- 只声明不赋值也会报错
- 只能先声明后使用,不会被提前解析
- 不能重复声明一个常量
注意:const声明的对象中属性是可以修改的
1.3 声明变量的六种方法
ES5:var function
ES6:let const import class
2、解构赋值
2.1 作用
从对象或数组中提取数组,并赋值给变量(多个)
2.2 对象的解构赋值
let { foo, bar } = { foo: 'aaa', bar: 'bbb' };
console.log(foo); //aaa
console.log(bar); //bbb
2.3 数组的解构赋值
let [, b, c] = [1, 2, 3];
conssole.log(b) //2
conssole.log(c) //3
2.4 函数参数的解构赋值
//数组
function add([x, y]){
return x + y;
}
add([1, 2]); // 3
//对象
function move({
x = 0, y = 0} = {
}) {
return [x, y];
}
move({
x: 3, y: 8}); // [3, 8]
move({
x: 3}); // [3, 0]
move({
}); // [0, 0]
move(); // [0, 0]
2.5 剩余运算符
//数组
let [a, ...b] = [1, 2, 3];
console.log(a); //1
console.log(b); //[2,3]
//对象
let {
a, b, ...rest} = {
a: 10, b: 20, c: 30, d: 40};
console.log(a); //10
console.log(b); //20
console.log(rest); //{c:30,d:40}
3、模板字符串
3.1 作用
简化字符串的拼接
3.2 使用
必须用 `` 包含,变化的部分用 ${XXX} 定义
// 多行字符串
`In JavaScript this is
not legal.`
// 字符串中嵌入变量
let name = "Bob", time = "today";
`Hello ${
name}, how are you ${
time}?`
// 调用函数
function fn() {
return "Hello World";
}
`foo ${
fn()} bar`
// foo Hello World bar
4、对象的扩展
4.1 简写
4.1.1 属性名简写
function f(x, y) {
return {
x, y};
}
// 等同于
function f(x, y) {
return {
x: x, y: y};
}
f(1, 2) // Object {x: 1, y: 2}
4.1.2 方法名简写
const person = {
sayHi() {
console.log("Hi");
}
}
person.sayHi(); //"Hi"
//等同于
const person = {
sayHi: function(){
console.log("Hi");
}
}
person.sayHi(); //"Hi"
4.2 对象的拓展运算符
//复制对象,浅拷贝,改变第一层就有影响
let person = {
name: "Amy", age: 15};
let someone = {
...person };
console.log(someone); //{name: "Amy", age: 15}
//可用于合并两个对象,浅拷贝,改变更深层次有影响
let age = {
age: 15};
let name = {
name: "Amy"};
let person = {
...age, ...name};
console.log(person); //{age: 15, name: "Amy"}
4.3 新增方法
4.3.1 Object.is()
比较两个值是否严格相等,与严格比较运算符(===)不同之处只有两个
Object.is(+0, -0) // false
Object.is(NaN, NaN) // true
4.3.2 Object.assign()
合并对象,浅拷贝,改变更深层次有影响
const target = {
a: 1 };
const source1 = {
b: 2 };
const source2 = {
c: 3 };
Object.assign(target, source1, source2);
console.log(target); // {a:1, b:2, c:3}
如果目标对象与源对象有同名属性,或多个源对象有同名属性,则后面的属性会覆盖前面的属性
4.3.3 Object.getOwnPropertyDescriptor()
对象的每个属性都有一个描述对象(Descriptor),用来控制该属性的行为
获取该属性的描述对象,描述对象的enumerable属性,称为“可枚举性”,如果该属性为false,就表示某些操作会忽略当前属性
let obj = {
foo: 123 };
Object.getOwnPropertyDescriptor(obj, 'foo') {
value: 123, //属性值
writable: true, //属性值为true,说明属性是可以重写的
enumerable: true, //属性值为true,说明属性是可以被枚举的
configurable: true //属性值为true,说明属性是可以被删除或可以被再次修改的
}
有四个操作会忽略enumerable为false的属性:
- for…in循环:只遍历对象自身的和继承的可枚举的属性
- Object.keys():返回对象自身的所有可枚举的属性的键名
- JSON.stringify():只串行化对象自身的可枚举的属性
- Object.assign(): 忽略enumerable为false的属性,只拷贝对象自身的可枚举的属性
4.3.4 Object.defineProperty()
定义或修改一个属性
Object.defineProperty(object, propertyName, attributesObject)
第一个参数是属性所在的对象
第二个参数是属性名
第三个参数是属性的描述对象
let o = Object.defineProperty({
}, 'p', {
value: 123,
writable: false,
enumerable: true,
configurable: false
});
console.log(o.p) // 123
o.p = 246;
console.log(o.p) // 123
// 因为writable为false,所以无法改变该属性的值
4.3.5 __proto__属性
读取或设置当前对象的prototype对象
let obj = {
money: 5000
}
let son = {
}
son.__proto__ = obj; //是浅拷贝
console.log(son.money); //5000
4.3.6 Object.keys() Object.values() Object.entries()
-
Object.keys()
- 返回一个数组,,成员是参数对象自身的(不含继承的)所有可遍历(enumerable)属性的键名
let arr = { foo: 'bar', baz: 42 }; console.log(Object.keys(arr));// ["foo", "baz"]
-
Object.values()
- 返回一个数组,成员是参数对象自身的(不含继承的)所有可遍历(enumerable)属性的键值
let arr = { foo: 'bar', baz: 42 }; console.log(Object.values(arr));// ["bar", 42]
-
Object.entries()
- 返回一个数组,成员是参数对象自身的(不含继承的)所有可遍历(enumerable)属性的键值对数组
let arr = { foo: 'bar', baz: 42 }; console.log(Object.entries(arr)); // [ ["foo", "bar"], ["baz", 42] ]
5、箭头函数
5.1 使用方法
代码块只有一句时可以省略 {}
5.1.1 一个参数
const f = v => v;
// 等同于
const f = function (v) {
return v;
};
5.1.2 没有参数
const f = () => console.log('我是箭头函数');
// 等同于
const f = function () {
console.log('我是箭头函数');
};
5.1.3 两个或以上参数
const sum = (num1, num2) => num1 + num2;
// 等同于
const sum = function(num1, num2) {
return num1 + num2;
};
5.2 注意点
5.2.1 返回对象处理
由于大括号被解释为代码块,必须在对象外面加上括号,否则会报错
// 报错
let getTempItem = id => {
id, name: "Temp" };
// 不报错
let getTempItem = id => ({
id, name: "Temp" });
5.2.2 this 指向
箭头函数的 this 就是定义时所在的对象,而不是使用时所在的对象
扩展:看外层是否有函数(作用域),如果有,最近的外层函数(作用域)的this指向就是箭头函数的this指向
function Timer() {
this.s1 = 0;
this.s2 = 0;
// 箭头函数,this 指向 Timer() 函数
setInterval(() => this.s1++, 1000);
// 普通函数
setInterval(function () {
this.s2++;
}, 1000);
}
let timer = new Timer();
setTimeout(() => console.log('s1: ', timer.s1), 3000);
setTimeout(() => console.log('s2: ', timer.s2), 3000);
// s1: 3
// s2: 0
//上面代码中,前者的this绑定定义时所在的作用域(即Timer函数),后者的this指向运行时所在的作用域(即全局对象)
5.2.3 其他注意点
- 不可以当作构造函数
- 不可以使用arguments对象
- 该对象在函数体内不存在。如果要用,可以用 rest 参数代替
5.3 应用场景
当把一个函数当做参数传递给另一个函数的时候,应用场景最广
setTimeout(() => {})
6、三点运算符
6.1 rest 参数
用来取代 arguments ,比 arguments 灵活,只能是最后部分形参参数
特点:arguments 返回的是伪数组,rest 参数返回的是真数组
function fn(...values) {
//定义时前面加三个点
console.log(values); //使用时直接用
values.forEach(function(value, index) {
console.log(value, index);
})
}
fn(1, 2, 3)
6.2 扩展运算
填充数组,把 arr1 的值填充到 arr
let arr = [1, 6];
let arr1 = [2, 3, 4, 5];
arr = [1, ...arr1, 6];
console.log(arr); //[1,2,3,4,5,6]
console.log(...arr); //1,2,3,4,5,6
7、Promise对象
Promise: ES6新增的API,是一个构造函数,容器中存放了一个异步任务
Promise 本身不是异步,往往内部都是封装一个异步任务
7.1 作用
将异步操作以同步的流程表达出来,避免了层层嵌套的回调函数(俗称“回调地狱”)
7.2 状态
- pending(进行中):等待状态,比如正在进行网络请求或者定时器没有到时间
- fulfilled (已成功):满足状态,当主动回调了 resolve 时,就处于该状态,并且回调.then()
- rejected(已失败):拒绝状态,当主动回调了 reject 时,就处于该状态,并且回调.catch()
Promise对象的状态改变,只有两种可能:从pending变为 fulfilled 和从pending变为rejected
7.3 语法
Promise构造函数接受一个函数作为参数,该函数的两个参数分别是resolve和reject。它们是两个函数,由 JavaScript 引擎提供,不用自己部署
7.3.1 创建 Promise
const promise = new Promise((resolve, reject) => {
if (/* 异步操作成功 */) {
//如果 true ,把容器的状态改为 resolve
resolve(value);
} else {
//如果 false ,把容器的状态改为 reject
reject(error);
}
})
resolve函数的作用是:将Promise对象的状态从“未完成”变为“成功”,在异步操作成功时调用,并将异步操作的结果,作为参数传递出去;
reject函数反之;
7.3.2 then 方法
Promise实例生成以后,可以用then方法分别指定resolve状态和reject状态的回调函数
promise.then((value) => {
// 成功的回调,接收的就是容器中的 resolve 函数
// 容器中 resolve 函数传的是什么,这里接收就是什么
console.log(value)
}, (error) => {
// 失败的回调,接收的就是容器中的 reject 函数
console.log(error)
});
7.3.3 链式写法
假设让下面三个异步操作按顺序执行(异步操作不会因代码写的顺序执行),就用 Promise 嵌套方式
//封装 Promise API
function fzPromise(isFlag,data,err) {
return new Promise((resolve, reject) => {
if (isFlag) {
resolve(data)
} else {
reject(err)
}
});
}
const promiseOne = new fzPromise(true,1,'操作失败');
const promiseTwo = new fzPromise(true, 2, '操作失败');
const promiseThree = new fzPromise(false, 3, '操作失败');
promiseOne
.then((data) => {
console.log(data);
//当 promiseOne 读取成功,当前函数 return 的结果就能在后面的 then 中的回调函数接收到
return promiseTwo
},(err) => {
console.log(err);
})
//这里是 promiseTwo 的 resolve
.then((data) => {
console.log(data);
return promiseThree
},(err) => {
console.log(err);
})
//这里是 promiseThree 的 resolve
.then((data) => {
console.log(data);
},(err) => {
//因为 promiseThree 是 false ,所以结果是 reject 传的 '操作失败'
console.log(err);
})
//1
//2
//操作失败
7.4 其他方法
7.4.1 Promise.resolve()
Promise.resolve('foo')
// 等价于
new Promise(resolve => resolve('foo'))
let thenable = {
then(resolve, reject) {
resolve(42);
}
};
let p1 = Promise.resolve(thenable);
p1.then(function(value) {
console.log(value); // 42
});
7.4.2 Promise.reject()
const p = Promise.reject('出错了');
// 等同于
const p = new Promise((resolve, reject) => reject('出错了'))
p.then(null, function (s) {
console.log(s)
})
// 出错了
7.4.3 Promise.all()
用于将多个 Promise 实例,包装成一个新的 Promise 实例, 接受一个数组作为参数, 可以不是数组,但必须具有 Iterator 接口
const p = Promise.all([p1, p2, p3]);
p
的状态由p1
、p2
、p3
决定,分成两种情况
- 只有
p1
、p2
、p3
的状态都变成fulfilled
,p
的状态才会变成fulfilled
,此时p1
、p2
、p3
的返回值组成一个数组,传递给p
的回调函数 - 只要
p1
、p2
、p3
之中有一个被rejected
,p
的状态就变成rejected
,此时第一个被reject
的实例的返回值,会传递给p
的回调函数
7.4.4 Promise.race()
const p = Promise.race([p1, p2, p3]);
同样是将多个 Promise 实例,包装成一个新的 Promise 实例, 只要p1
、p2
、p3
之中有一个实例率先改变状态,p
的状态就跟着改变。那个率先改变的 Promise 实例的返回值,就传递给p
的回调函数
7.4.5 Promise.allSettled()
Promise.allSettled()
方法接受一组 Promise 实例作为参数,包装成一个新的 Promise 实例。只有等到所有这些参数实例都返回结果,不管是fulfilled
还是rejected
,包装实例才会结束
8、Symbol 数据类型
ES5 中对象的属性名都是字符串,容易造成重名,污染环境
8.1 特点
- Symbol 属性值对应的值是唯一的,解决命名冲突问题
- Symbol 值不能与其它数据类型进行计算,包括同字符串拼接
- for in ,for of 遍历时不会遍历 Symbol
const obj = {
};
const foo = Symbol('foo');
obj[foo] = 'bar';
for (let i in obj) {
console.log(i); // 无输出
}
8.2 使用方法
Symbol函数前不能使用new命令,否则会报错。这是因为生成的 Symbol 是一个原始类型的值,不是对象
8.2.1 带参数
let s1 = Symbol('foo'); //标识
let s2 = Symbol('bar'); //标识
console.log(s1) // Symbol(foo)
console.log(s2) // Symbol(bar)
// 如果不加参数,它们在控制台的输出都是Symbol(),不利于区分
8.2.2 不带参数
let s1 = Symbol();
let s2 = Symbol();
console.log(s1) // Symbol()
console.log(s2) // Symbol()
console.log(s1 === s2) // false
8.3 内置的 Symbol 值
除了定义自己使用的 Symbol 值以外,ES6 还提供了 11 个内置的 Symbol 值,指向语言内部使用的方法
8.3.1 Symbol.iterator
指向该对象的默认遍历器方法, 对象进行for...of
循环时,会调用Symbol.iterator
方法,返回该对象的默认遍历器
const myIterable = {
};
myIterable[Symbol.iterator] = function* () {
yield 1;
yield 2;
yield 3;
};
for (let i of myIterable) {
console.log(i);
}
//1
//2
//3
console.log([...myIterable]) // [1, 2, 3]
8.4 消除魔术字符串
魔术字符串指的是:在代码之中多次出现,与代码形成强耦合的某一个具体的字符串或者数值
function getArea(shape, options) {
let area = 0;
switch (shape) {
case 'Triangle': // 魔术字符串
area = .5 * options.width * options.height;
break;
}
return area;
}
getArea('Triangle', {
width: 100, height: 100 }); // 魔术字符串
上面代码中,字符串Triangle就是一个魔术字符串。它多次出现,与代码形成“强耦合”,不利于将来的修改和维护
常用的消除魔术字符串的方法,就是把它写成一个变量
const shapeType = {
triangle: Symbol('triangle')
};
function getArea(shape, options) {
let area = 0;
switch (shape) {
case shapeType.triangle:
area = .5 * options.width * options.height;
break;
}
return area;
}
getArea(shapeType.triangle, {
width: 100, height: 100 });
9、Iterator 和 for…of 循环
9.1 概念
遍历器(Iterator)是一种接口,为各种不同的数据结构提供统一的访问机制。任何数据结构只要部署 Iterator 接口,就可以完成遍历操作(即依次处理该数据结构的所有成员)。
9.2 作用
- 为各种数据结构,提供一个统一的、简便的访问接口
- 使得数据结构的成员能够按某种次序排列
- ES6 创造了一种新的遍历命令
for...of
循环,Iterator 接口主要供for...of
消费
9.3 遍历过程
- 创建一个指针对象,指向当前数据结构的起始位置。也就是说,遍历器对象本质上,就是一个指针对象。
- 第一次调用指针对象的
next
方法,可以将指针指向数据结构的第一个成员。 - 第二次调用指针对象的
next
方法,指针就指向数据结构的第二个成员。 - 不断调用指针对象的
next
方法,直到它指向数据结构的结束位置。
具体来说,就是返回一个包含value和done两个属性的对象。其中,value属性是当前成员的值,done属性是一个布尔值,表示遍历是否结束。
例子:
function makeIterator(array) {
let nextIndex = 0;
return {
next: function() {
return nextIndex < array.length ?
{
value: array[nextIndex++], done: false} :
{
value: undefined, done: true};
}
};
}
var it = makeIterator(['a', 'b']);
console.log(it.next()) // { value: "a", done: false }
console.log(it.next()) // { value: "b", done: false }
console.log(it.next()) // { value: undefined, done: true }
9.4 默认有 Iterator 接口
原生具备iterator
接口(即默认部署了Symbol.iterator
属性),for...of
循环本质上就是调用这个接口产生的遍历器
- Array
- Map
- Set
- String
- TypedArray
- 函数的 arguments 对象
- NodeList 对象
对象(Object)之所以没有默认部署 Iterator 接口,是因为对象的哪个属性先遍历,哪个属性后遍历是不确定的,需要开发者手动指定
const arr = ['red', 'green', 'blue'];
for(let v of arr) {
console.log(v); // red green blue
}
const obj = {
};
obj[Symbol.iterator] = arr[Symbol.iterator].bind(arr);
for(let v of obj) {
console.log(v); // red green blue
}
10、Generator函数
10.1 概念
Generator 函数是一个状态机,封装了多个内部状态 , 执行 Generator 函数会返回一个遍历器对象 , 可以依次遍历 Generator 函数内部的每一个状态
特征:
function
关键字与函数名之间有一个星号- 函数体内部使用
yield
表达式,定义不同的内部状态(yield
在英语里的意思就是“产出”)
function* helloWorldGenerator() {
yield 'hello';
yield 'world';
return 'ending';
}
var hw = helloWorldGenerator();
hw.next()
// { value: 'hello', done: false }
hw.next()
// { value: 'world', done: false }
hw.next()
// { value: 'ending', done: true }
hw.next()
// { value: undefined, done: true }
调用 Generator 函数后,该函数并不执行,返回的也不是函数运行结果,而是一个指向内部状态的指针对象。必须调用遍历器对象的next
方法,使得指针移向下一个状态, 直到遇到下一个yield
表达式(或return
语句)为止
写法:
function * foo(x, y) {
··· }
function *foo(x, y) {
··· }
function* foo(x, y) {
··· } //通用
function*foo(x, y) {
··· }
10.2 yield 表达式
只能用在 Generator 函数里面,用在其他地方都会报错
与 return 的区别:
- 相似之处在于,都能返回紧跟在语句后面的那个表达式的值
- 区别在于每次遇到
yield
,函数暂停执行,下一次再从该位置继续向后执行,而return
语句不具备位置记忆的功能 - 一个函数里面,只能执行一次 return
语句,但是可以执行多次 yield
表达式
位置
yield
表达式如果用在另一个表达式之中,必须放在圆括号里面
console.log('Hello' + (yield));
yield
表达式用作函数参数或放在赋值表达式的右边,可以不加括号
let input = yield;
10.3 next 方法的参数
yield
表达式本身没有返回值,或者说总是返回undefined
。next
方法可以带一个参数,该参数就会被当作上一个yield
表达式的返回值
function* foo(x) {
var y = 2 * (yield (x + 1));
var z = yield (y / 3);
return (x + y + z);
}
var a = foo(5);
a.next() // Object{value:6, done:false} 返回 5 + 1,即 6
a.next() // Object{value:NaN, done:false} 返回 2 * undefined / 3,即 NaN
a.next() // Object{value:NaN, done:true} 返回 5 + NaN + undefined,即 NaN
var b = foo(5);
b.next() // { value:6, done:false } 返回 5 + 1,即 6
b.next(12) // { value:8, done:false } 返回 2 * 12 / 3,即 8
b.next(13) // { value:42, done:true } 返回 5 + 24 + 13,即 42
10.4 应用
-
异步操作的同步化表达
//封装异步操作 function getNews(url) { $.get(url, function(res) { let url = 'http://localhost:8080' + res.commentsUrl; //第二次请求地址 SX.next(url); //调用第二个 yield ,把拿到的第二次请求地址当参数传入 }) } function* sendXml() { let url = yield getNews('http://localhost:8080?id=3'); //第一次请求 yield getNews(url); //发送第二次请求 } let SX = sendXml(); SX.next();
-
部署 Iterator 接口
- 利用 Generator 函数,可以在任意对象上部署 Iterator 接口
function* iterEntries(obj) { let keys = Object.keys(obj); for (let i=0; i < keys.length; i++) { let key = keys[i]; yield [key, obj[key]]; } } let myObj = { foo: 3, bar: 7 }; for (let [key, value] of iterEntries(myObj)) { console.log(key, value); } // foo 3 // bar 7
11、async 函数
11.1 改进
async
函数对 Generator 函数的改进,体现在以下四点
- 内置执行器
- 调用就执行, 不像 Generator 函数,需要调用
next
方法
- 调用就执行, 不像 Generator 函数,需要调用
- 更好的语义
async
表示函数里有异步操作,await
表示紧跟在后面的表达式需要等待结果
- 更广的适用性
- 返回值是 Promise
- Generator 函数的返回值是 Iterator 对象,
async
函数可以用then
方法指定下一步的操作
- Generator 函数的返回值是 Iterator 对象,
11.2 基本用法
async
函数返回一个 Promise 对象,可以使用then
方法添加回调函数。当函数执行的时候,一旦遇到await
就会先返回,等到异步操作完成,再接着执行函数体内后面的语句。
async function getNews(url) {
return new Promise((resolve, reject) => {
$.ajax({
type: "get",
url,
success: data => {
resolve(data)
}
});
})
}
async function sendXml() {
let result = await getNews('http://localhost:8080?id=3'); //第一次请求
result = await getNews('http://localhost:8080?id=3' + result.commentsUrl); //第二次请求
}
sendXml();
12、Module (模块)
12.1 与 CommonJS 模块的差异
CommonJS 模块输出的是一个值的拷贝,ES6 模块输出的是值的引用。
CommonJS 模块是运行时加载,ES6 模块是编译时输出接口。
12.2 优点
- 避免变量污染,命名冲突
- 提供代码的复用率,维护性
- 依赖关系管理
12.3 export 与 import
- 变量名导出
export.js => //公用的 js
//export 用于导出
export let uname = 'zhangsan';
export let age = 18;
import.js =>
//import 用于导入
import {
uname,age} form './export.js'
console.log(`我叫${
uname},今年${
age}`) //我叫zhangsan,今年18
- 花括号导出
export.js => //公用的 js
//export 用于导出
let uname = 'zhangsan';
let age= 18;
export {
uname,age}
import.js =>
//import 用于导入
import {
uname as myname,age} form './export.js'
console.log(`我叫${
myname},今年${
age}`) //我叫zhangsan,今年18
- 对象型导出
export.js => //公用的 js
//export 用于导出
let obj = {
uname : 'zhangsan'.
age: 18;
}
export {
obj}
import.js =>
//import 用于导入
import {
obj} form './export.js'
obj.age = 50;
console.log(obj)
//
{
uname : 'zhangsan'.
age: 50;
}
-
script 标签使用
//module.js export default function test(){ return 'test...' } // index.js import test from './module.js'; console.log(test()) // 方法 1 : 引入module.js,然后在script标签里面调用 <script type="module"> import test from './module.js'; console.log(test()) </script> // 方法 2 : 直接引入index.js,使用src引入 <script type="module" src="./index.js"></script>
-
默认导出
export default //由导入的地方起名字
13、Set 和 Map
13.1 Set
无序的不可重复的多个 value 的集合体,似于数组
13.1.1 基本用法
-
创建 new Set(Array)
let set = new Set([1,3,2,5,6,3]); console.log(set); //Set(5) {1,3,2,5,6}
-
添加 add(value)
let set = new Set([1,3,2,5,6,3]); set.add(7) console.log(set); //Set(6) {1,3,2,5,6,7}
-
删除 delete(value)
let set = new Set([1,3,2,5,6,3]); set.delete(3) console.log(set); //Set(4) {1,2,5,6}
-
检索 has(value)
let set = new Set([1,3,2,5,6,3]); console.log(set.has(3)); //true console.log(set.has(8)); //false
-
清除 clear()
let set = new Set([1,3,2,5,6,3]); set.clear(); console.log(set); //Set(0) {}
-
数据长度 size
let set = new Set([1, 3, 2, 5, 6, 3]); console.log(set.size); //5
13.1.2 应用
去除数组的重复成员
let arr = [1, 2, 4, 4, 1, 3];
let newArr = [...new Set(arr)]
console.log(newArr); //[1,2,4,3]
13.2 Map
无序的 key 不重复的多个 key-value 的集合体
13.2.1 基本用法
-
创建 new Map(Array)
//数组里套数组,1,2是 key,名字是 value let map = new Map([[1,'zhangsan'],[2,'lisi']]); console.log(map); //Map(2) {1 => "zhangsan", 2 => "lisi"}
-
添加 set(key,value)
let map = new Map([ [1, 'zhangsan'], [2, 'lisi'] ]); map.set(3, 'wangwu') console.log(map); //Map(3) {1 => "zhangsan", 2 => "lisi", 3 => "wangwu"}
-
检索 get(key)
返回检索到的元素,没有返回 undefined
let map = new Map([ [1, 'zhangsan'], [2, 'lisi'] ]) console.log(map.get(2)) //lisi
-
检索 has(key)
let map = new Map([ [1, 'zhangsan'], [2, 'lisi'] ]) console.log(map.has(2)) //true
-
删除 delete(key)
let map = new Map([ [1, 'zhangsan'], [2, 'lisi'] ]); map.delete(2) console.log(map); //Map(1) {1 => "zhangsan"}
-
清除 clear()
let map = new Map([ [1, 'zhangsan'], [2, 'lisi'] ]); map.clear() console.log(map); //Map(0) {}
-
数据长度 size
let map = new Map([ [1, 'zhangsan'], [2, 'lisi'] ]); console.log(map.size); //2