669 lines
14 KiB
Markdown
669 lines
14 KiB
Markdown
# ES6
|
||
|
||
参考: 阮一峰es6 https://wangdoc.com/es6/
|
||
|
||
## let const
|
||
|
||
推荐使用let const 关键字替代 var关键字声明变量,因为 var存在诸多问题
|
||
|
||
* 越域
|
||
|
||
```js
|
||
{
|
||
var a = 1;
|
||
let b = 2;
|
||
}
|
||
console.log(a); // 1
|
||
console.log(b); // ReferenceError: b is not defined
|
||
```
|
||
|
||
* var 可以声明多次
|
||
* var 会变量提升
|
||
|
||
## 解构
|
||
|
||
> 把复合数据类型(对象居多, 数组较少)快速解析成单个变量,而无需使用arr[x]或者obj[key]等传统方式进行赋值
|
||
|
||
### 数组解构赋值
|
||
|
||
```js
|
||
var arr = ['this is a string', 2, 3];
|
||
//传统方式
|
||
var a = arr[0],
|
||
b = arr[1],
|
||
c = arr[2];
|
||
//解构赋值,是不是简洁很多?
|
||
var [a, b, c] = arr;
|
||
console.log(a);//this is a string
|
||
console.log(b);//2
|
||
console.log(c);//3
|
||
|
||
// 如果想跳过某个元素, 只需多写一个逗号
|
||
```
|
||
|
||
### 嵌套数组解构
|
||
|
||
```js
|
||
var arr = [[1, 2, [3, 4]], 5, 6];
|
||
var [[d, e, [f, g]], h, i] = arr;
|
||
console.log(d);//1
|
||
console.log(f);//3
|
||
console.log(i);//6
|
||
```
|
||
|
||
### 函数传参解构
|
||
|
||
```js
|
||
var arr = ['this is a string', 2, 3];
|
||
function fn1([a, b, c]) {
|
||
console.log(a);
|
||
console.log(b);
|
||
console.log(c);
|
||
}
|
||
fn1(arr);
|
||
//this is a string
|
||
//2
|
||
//3
|
||
```
|
||
|
||
### for循环解构
|
||
|
||
```js
|
||
var arr = [[11, 12], [21, 22], [31, 32]];
|
||
for (let [a, b] of arr) {
|
||
console.log(a);
|
||
console.log(b);
|
||
}
|
||
//11
|
||
//12
|
||
//21
|
||
//22
|
||
//31
|
||
//32
|
||
```
|
||
|
||
### 对象赋值解构
|
||
|
||
对象的解构必须要用属性名, 不是根据顺序, 而是属性名对应
|
||
|
||
```js
|
||
var obj = {
|
||
name: 'chris',
|
||
sex: 'male',
|
||
age: 26,
|
||
son: {
|
||
sonname: '大熊',
|
||
sonsex: 'male',
|
||
sonage: 1
|
||
}
|
||
};
|
||
var {name, sex, age, son} = obj;
|
||
console.log(name + ' ' + sex + ' ' + age); //chris male 26
|
||
console.log(son); // { sonname: '大熊', sonsex: 'male', sonage: 1 }
|
||
```
|
||
|
||
### 对象传参解构
|
||
|
||
```js
|
||
var obj = {
|
||
name: 'chris',
|
||
sex: 'male',
|
||
age: 26,
|
||
son: {
|
||
sonname: '大熊',
|
||
sonsex: 'male',
|
||
sonage: 1
|
||
}
|
||
};
|
||
function fn2({sex, age, name}) {
|
||
console.log(name + ' ' + sex + ' ' + age);
|
||
}
|
||
fn2(obj);
|
||
//chris male 26
|
||
```
|
||
|
||
### 解构重命名变量
|
||
|
||
```js
|
||
var obj = {
|
||
name: 'chris',
|
||
sex: 'male',
|
||
age: 26
|
||
};
|
||
var {name: nickname, age: howold} = obj;
|
||
console.log(nickname + ' ' + howold); //chris 26
|
||
```
|
||
|
||
对象的解构赋值是下面形式的简写
|
||
|
||
```js
|
||
let { foo: foo, bar: bar } = { foo: 'aaa', bar: 'bbb' }
|
||
```
|
||
|
||
对象的解构赋值的内部机制,是先找到同名属性,然后再赋给对应的变量。真正被赋值的是后者,而不是前者。
|
||
|
||
```js
|
||
let { foo: baz } = { foo: 'aaa', bar: 'bbb' }
|
||
baz // "aaa"
|
||
foo // error: foo is not defined
|
||
```
|
||
|
||
```js
|
||
const node = {
|
||
loc: {
|
||
start: {
|
||
line: 1,
|
||
column: 5
|
||
}
|
||
}
|
||
}
|
||
|
||
let {
|
||
loc,
|
||
loc: { start },
|
||
loc: {
|
||
start: { line }
|
||
}
|
||
} = node
|
||
line // 1
|
||
loc // Object {start: Object}
|
||
start // Object {line: 1, column: 5}
|
||
```
|
||
|
||
上面代码有三次解构赋值,分别是对 loc、start、line 三个属性的解构赋值。注意,最后一次对 line 属性的解构赋值之中,只有 line 是变量,loc 和 start 不是变量。
|
||
|
||
### 嵌套对象解构
|
||
|
||
```js
|
||
var obj = {
|
||
name: 'chris',
|
||
sex: 'male',
|
||
age: 26,
|
||
son: {
|
||
sonname: '大熊',
|
||
sonsex: 'male',
|
||
sonage: 1
|
||
}
|
||
};
|
||
var {name, sex, age, son: {sonname, sonsex, sonage}} = obj;
|
||
console.log(sonname + ' ' + sonsex + ' ' + sonage);
|
||
//大熊 male 1
|
||
//Babel暂不支持这种嵌套解构
|
||
obj = {
|
||
name: 'chris',
|
||
sex: 'male',
|
||
age: [1, 2, 3]
|
||
}
|
||
{name, sex, age: [a, b, c]} = obj;
|
||
console.log(c);
|
||
```
|
||
|
||
### 对象属性重名
|
||
|
||
需要更改变量名:
|
||
|
||
```js
|
||
var obj = {
|
||
name: 'chris',
|
||
sex: 'male',
|
||
age: 26,
|
||
son: {
|
||
name: '大熊',
|
||
sex: 'male',
|
||
age: 1
|
||
}
|
||
};
|
||
//赋值解构
|
||
var {name: fathername, son: {name, sex, age}} = obj;
|
||
console.log(fathername); //chris
|
||
console.log(name); //大熊
|
||
//传参解构
|
||
function fn3({sex, age, name, son: {name: sonname}}) {
|
||
console.log(name + ' ' + sex + ' ' + age + ' ' + sonname);
|
||
}
|
||
fn3(obj);
|
||
//chris male 26 大熊
|
||
```
|
||
|
||
### 循环解构对象
|
||
|
||
```js
|
||
var arr = [{name: 'chris', age: 26}, {name: 'jack', age: 27}, {name: 'peter',age: 28}];
|
||
|
||
for (let {age, name} of arr) {
|
||
console.log(name + ' ' + age);
|
||
}
|
||
//chris 26
|
||
//jack 27
|
||
//peter 28
|
||
```
|
||
|
||
### 定义默认值
|
||
|
||
> 在解构过程中,如果某个路径上的属性不存在,可以使用默认值。
|
||
|
||
```js
|
||
const user = {
|
||
id: 123,
|
||
name: 'hehe'
|
||
};
|
||
const {
|
||
education: {
|
||
school: {
|
||
name
|
||
}
|
||
} = {
|
||
school: {
|
||
name: 'NB'
|
||
}
|
||
}
|
||
} = user;
|
||
console.log(name); //prints: NB
|
||
```
|
||
|
||
### 解构的特殊应用场景
|
||
|
||
```js
|
||
//变量互换
|
||
var x = 1,
|
||
y = 2;
|
||
var [x, y] = [y, x];
|
||
console.log(x); //2
|
||
console.log(y); //1
|
||
//字符串解构
|
||
var str = 'love';
|
||
var [a, b, c, d] = str;
|
||
console.log(a);//l
|
||
console.log(b);//o
|
||
console.log(c);//v
|
||
console.log(d);//e
|
||
```
|
||
|
||
## 展开运算符
|
||
|
||
展开运算符用三个点号表示,功能是把数组或类数组对象展开成一系列用逗号隔开的值
|
||
|
||
```js
|
||
var foo = function(a, b, c) {
|
||
console.log(a);
|
||
console.log(b);
|
||
console.log(c);
|
||
}
|
||
var arr = [1, 2, 3];
|
||
//传统写法
|
||
foo(arr[0], arr[1], arr[2]);
|
||
//使用展开运算符
|
||
foo(...arr);
|
||
//1
|
||
//2
|
||
//3
|
||
```
|
||
|
||
特殊应用场景:
|
||
|
||
```js
|
||
//数组深拷贝
|
||
var arr2 = arr;
|
||
var arr3 = [...arr];
|
||
console.log(arr===arr2); //true, 说明arr和arr2指向同一个数组
|
||
console.log(arr===arr3); //false, 说明arr3和arr指向不同数组
|
||
|
||
//把一个数组插入另一个数组字面量
|
||
var arr4 = [...arr, 4, 5, 6];
|
||
console.log(arr4);//[1, 2, 3, 4, 5, 6]
|
||
|
||
//字符串转数组
|
||
var str = 'love';
|
||
var arr5 = [...str];
|
||
console.log(arr5);//[ 'l', 'o', 'v', 'e' ]
|
||
```
|
||
|
||
## 剩余运算符
|
||
|
||
剩余运算符也是三个点号,不过其功能与展开运算符恰好相反,把逗号隔开的值序列组合成一个数组
|
||
|
||
```js
|
||
//主要用于不定参数,所以ES6开始可以不再使用arguments对象
|
||
var bar = function(...args) {
|
||
for (let el of args) {
|
||
console.log(el);
|
||
}
|
||
}
|
||
bar(1, 2, 3, 4);
|
||
//1
|
||
//2
|
||
//3
|
||
//4
|
||
|
||
bar = function(a, ...args) {
|
||
console.log(a);
|
||
console.log(args);
|
||
}
|
||
bar(1, 2, 3, 4);
|
||
//1
|
||
//[ 2, 3, 4 ]
|
||
```
|
||
|
||
剩余运算符配合解构使用:
|
||
|
||
```js
|
||
var [a, ...rest] = [1, 2, 3, 4];
|
||
console.log(a);//1
|
||
console.log(rest);//[2, 3, 4]
|
||
```
|
||
|
||
## 结构展开运算符小结
|
||
|
||
等号表达式是典型的赋值形式,函数传参和for循环的变量都是特殊形式的赋值。解构的原理是赋值的两边具有相同的解构,就可以正确取出数组或对象里面的元素或属性值,省略了使用下标逐个赋值的麻烦。
|
||
|
||
==对于三个点号,三点放在形参或者等号左边为剩余运算符; 放在实参或者等号右边为展开运算符。==
|
||
|
||
## 结构展开运算符经验
|
||
|
||
* 在等号赋值或for循环中,如果需要从数组或对象中取值,尽量使用解构。
|
||
* 在自己定义函数的时候,如果调用者传来的是数组或对象,形参尽量使用解构方式,优先使用对象解构,其次是数组解构。代码可读性会很好。
|
||
* 在调用第三方函数的时候,如果该函数接受多个参数,并且你要传入的实参为数组,则使用展开运算符。可以避免使用下标形式传入参数。也可以避免很多人习惯的使用apply方法传入数组。
|
||
* 剩余运算符使用场景应该稍少一些,主要是处理不定数量参数,可以避免arguments对象的使用。
|
||
|
||
## 可选链操作符
|
||
|
||
> 读取对象内部的某个属性,往往需要判断一下,属性的上层对象是否存在,当其中一链为null或者undefined时就返回undefined,这样即使中间缺少一个属性也不会报错
|
||
|
||
```js
|
||
const firstName = message?.body?.user?.firstName || 'default';
|
||
```
|
||
|
||
## 空值合并操作符
|
||
|
||
> 空值合并操作符(`??`)是一个逻辑操作符,当左侧的操作数为null或者undefined时,返回其右侧操作数,否则返回左侧操作数。
|
||
|
||
如果使用 `||` 来为某些变量设置默认值,可能会遇到意料之外的行为。比如为假值(例如,`''` 或 `0`)时。
|
||
|
||
```js
|
||
const value1 = 0 || 'default'; // 'default'(因为 0 是假值)
|
||
const value2 = 0 ?? 'default'; // 0(因为 0 不是 null 或 undefined)
|
||
|
||
const value3 = '' || 'default'; // 'default'(因为空字符串是假值)
|
||
const value4 = '' ?? 'default'; // ''(因为空字符串不是 null 或 undefined)
|
||
|
||
const value5 = null ?? 'default'; // 'default'(因为 null 是空值)
|
||
const value6 = undefined ?? 'default'; // 'default'(因为 undefined 是空值)
|
||
```
|
||
|
||
## 函数的默认值
|
||
|
||
```js
|
||
function show(msg = "...") {
|
||
console.log(msg)
|
||
}
|
||
show()
|
||
show('test')
|
||
```
|
||
|
||
* 如果一个函数有多个形参也有默认值: 默认值一定要在后面
|
||
|
||
```js
|
||
function test(a, b, c =1){}
|
||
// 不能是 function test(a=1, b, c){}
|
||
```
|
||
|
||
## 箭头函数/lamda表示式
|
||
|
||
```js
|
||
// 两个参数的情况:
|
||
let sum = function (a, b) {
|
||
return a + b;
|
||
}
|
||
// 简写为:
|
||
//当只有一行语句,并且需要返回结果时,可以省略 {} , 结果会自动返回。
|
||
let sum2 = (a, b) => a + b;
|
||
//测试调用
|
||
console.log(sum2(10, 10));//20
|
||
// 代码不止一行,可以用`{}`括起来
|
||
let sum3 = (a, b) => {
|
||
c = a + b;
|
||
return c;
|
||
};
|
||
//测试调用
|
||
console.log(sum3(10, 20));//30
|
||
```
|
||
|
||
## 模板字符串
|
||
|
||
```js
|
||
`${变量}`
|
||
|
||
let info = "你好,我的名字是:【"+name+"】,年龄是:【"+age+"】,邮箱是:【】"
|
||
console.log(info);
|
||
|
||
# 模板字符串的写法
|
||
let info = `你好,我的名字是:${name},年龄是:${person.age},邮箱是:${person.email}`
|
||
console.log(info);
|
||
```
|
||
|
||
## fetch api
|
||
|
||
另建笔记
|
||
|
||
## Promise
|
||
|
||
另建笔记
|
||
|
||
## async
|
||
|
||
另建笔记
|
||
|
||
## Set
|
||
|
||
> 可以理解为不重复的数组
|
||
|
||
```js
|
||
const set = new Set([1, 5, 3, 4])
|
||
set.add(5) // 不能重复
|
||
set.delete(3) // 按照内容删除, 没有下标概念, 遍历获取不了index
|
||
set.has(4) // true
|
||
console.log(set)
|
||
```
|
||
|
||
使用: 数组去重
|
||
|
||
## Map
|
||
|
||
> 键值对的集合
|
||
|
||
Map和Object的区别
|
||
|
||
* Map 的键可以是任意值,包括函数、对象或任意基本类型
|
||
* Object 的键必须是一个 String 或是 Symbol
|
||
* Map 的键值对个数可以轻易地通过 size 属性获取
|
||
* Object 的键值对个数只能手动计算
|
||
* Map 是 可迭代的 的,所以可以直接被迭代
|
||
* Object 没有实现迭代协议, 所以不能用 for...of 表达式
|
||
* Map 在频繁增删键值对的场景下性能更好
|
||
* Map 没有元素的序列化和解析的支持
|
||
|
||
```js
|
||
const map = new Map()
|
||
map.set('a', 1) // 添加
|
||
map.set('b', 2)
|
||
map.has('a') // 判断是否存在
|
||
map.get('a') // 获取值
|
||
map.size // 获取长度
|
||
map.keys() // 获取keys
|
||
map.forEach((value,key)=>{console.log(`${key}=${value}`)}) // 遍历
|
||
map.delete('a') // 删除
|
||
map.clear() // 清空
|
||
```
|
||
|
||
## Symbol
|
||
|
||
> 表示唯一的不可变的值, 通常用于创建对象的唯一属性键
|
||
|
||
* 每个 `symbol` 的值都是唯一的, 即使他们的描述相同
|
||
* 可以用于对象的键名, 避免冲突
|
||
|
||
```js
|
||
const sym1 = Symbol('key')
|
||
const sym2 = Symbol('key')
|
||
|
||
console.log(sym1 === sym2) // false
|
||
|
||
const obj = { [sym1]: 1, [sym2]: 2}
|
||
```
|
||
|
||
## BigInt
|
||
|
||
> 表示任意精度的整数, 可以表示大于 `Number.MAX_SAFE_INTEGER` (9007199254740991) 的整数, 或者小于 `Number.MIN_SAFE_INTEGER` (-9007199254740991) 的负整数
|
||
|
||
* 在数字后面加 `n` 来创建
|
||
* 不能和 `Number` 混合运算
|
||
|
||
```js
|
||
const big = 9007199254740992n
|
||
console.log(big)
|
||
console.log(big + 1n)
|
||
```
|
||
|
||
## Class
|
||
|
||
另建笔记
|
||
|
||
## Proxy
|
||
|
||
> 创建一个对象的代理,从而实现基本操作的拦截和自定义(如属性查找、赋值、枚举、函数调用等)
|
||
|
||
```js
|
||
const p = new Proxy(target, handler)
|
||
```
|
||
|
||
```js
|
||
let target = { name: "Alice", age: 25 };
|
||
|
||
let handler = {
|
||
get(target, prop) {
|
||
console.log(`读取属性:${prop}`);
|
||
return target[prop];
|
||
},
|
||
set(target, prop, value) {
|
||
console.log(`设置属性:${prop} = ${value}`);
|
||
target[prop] = value;
|
||
return true; // 表示设置成功
|
||
}
|
||
};
|
||
|
||
let proxy = new Proxy(target, handler);
|
||
|
||
proxy.name; // 读取属性:name
|
||
proxy.age = 30; // 设置属性:age = 30
|
||
```
|
||
|
||
## for...of
|
||
|
||
> 执行一个循环,该循环处理来自可迭代对象的值序列。可迭代对象包括内置对象的实例,例如 Array、String、TypedArray、Map、Set、NodeList(以及其他 DOM 集合),还包括 arguments 对象、由生成器函数生成的生成器,以及用户定义的可迭代对象
|
||
|
||
```js
|
||
const array1 = ["a", "b", "c"];
|
||
|
||
for (const element of array1) {
|
||
console.log(element);
|
||
}
|
||
```
|
||
|
||
* **支持所有可迭代对象**:`for...of` 不仅可以遍历数组,还可以遍历其他可迭代对象,如 `Map`、`Set`、字符串等。
|
||
* **支持 `break` 和 `continue`**:在 `for...of` 循环中,你可以使用 `break` 来提前终止循环,或者使用 `continue` 跳过当前迭代。
|
||
* **支持异步操作**:在 `for...of` 循环中,你可以使用 `await` 来处理异步操作,而 `forEach` 不支持。
|
||
|
||
`for .. in` 是 es5 就有的, 专门用来遍历对象的. 也可间接通过 `Object.keys(obj)` 来遍历
|
||
|
||
```js
|
||
const object = { a: 1, b: 2, c: 3 };
|
||
|
||
for (const property in object) {
|
||
console.log(`${property}: ${object[property]}`);
|
||
}
|
||
```
|
||
|
||
## import export
|
||
|
||
```js
|
||
// import * as from 路径
|
||
import * as dayjs from 'dayjs'
|
||
|
||
// export * form 路径
|
||
export * from "./demandConfirmRecord"
|
||
```
|
||
|
||
## 模块化
|
||
|
||
`type="module"`
|
||
|
||
将 JavaScript 程序拆分为可按需导入的单独模块的机制
|
||
|
||
```html
|
||
<!DOCTYPE html>
|
||
<html lang="en">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<title>Title</title>
|
||
<script src="libs/user.js" type="module"/>
|
||
</head>
|
||
<body>
|
||
<h1>模块化测试</h1>
|
||
</body>
|
||
</html>
|
||
```
|
||
|
||
```js
|
||
const user = {
|
||
username: "张三",
|
||
age: 18
|
||
}
|
||
|
||
const isAdult = (age)=>{
|
||
if (age > 18){
|
||
console.log("成年人")
|
||
}else {
|
||
console.log("未成年")
|
||
}
|
||
}
|
||
|
||
|
||
export {user,isAdult}
|
||
|
||
// Java 怎么模块化;
|
||
// 1、druid.jar
|
||
// 2、import 导入类
|
||
|
||
// JS 模块化;
|
||
// 1、 xxx.js
|
||
// 2、 xxx.js 暴露功能;
|
||
// 3、import 导入 xxx.js 的功能
|
||
//xxx.js 暴露的功能,别人才能导入
|
||
```
|
||
|
||
## import() 动态导入
|
||
|
||
* 动态导入是 ES2020 引入的功能,允许在运行时动态加载模块。
|
||
* 使用 `import()` 函数,它返回一个 `Promise`,解析为模块的命名空间对象。
|
||
* 动态导入的路径可以是变量或表达式。
|
||
|
||
特点:
|
||
|
||
* **异步加载**:`import()` 是异步的,不会阻塞主线程。
|
||
* **按需加载**:可以在需要时加载模块,减少初始加载时间。
|
||
* **条件加载**:可以根据条件动态加载不同的模块。
|
||
|
||
```js
|
||
import { foo } from './module.js';
|
||
```
|
||
|
||
```js
|
||
const modulePath = './module.js';
|
||
import(modulePath)
|
||
.then(module => {
|
||
module.foo();
|
||
})
|
||
.catch(err => {
|
||
console.error('Failed to load module', err);
|
||
});
|
||
``` |