关键字let和const

let关键字

声明变量用let

特点:
不允许重复声明
块儿级作用域
不存在变量提升
不影响作用域链

const关键字

声明常量用const
特点:
不允许重复声明
块儿级作用域
声明必须赋初始值
值不允许修改
标识符一般为大写

变量的解构赋值

ES6 允许按照一定模式,从数组和对象中提取值,对变量进行赋值,称为解构赋值。

频繁使用对象方法、数组元素时,可以使用解构赋值形式

数组的解构赋值

1
2
3
4
5
6
//数组的解构赋值
const arr = ["西瓜", "鸭梨", "哈密瓜"];
let [xg, yl, hmg] = arr;
console.log(xg); //西瓜
console.log(yl); //鸭梨
console.log(hmg); //哈密瓜

简单对象的解构赋值

1
2
3
4
5
6
7
8
//对象的解构赋值
const xi = {
name: "西西",
tags: ["小说", "音乐", "游戏", "旅行"]
};
let {name, tags} = xi;
console.log(name);
console.log(tags);

复杂对象的解构赋值:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//复杂对象的解构赋值
let xixi = {
name: "西西",
age: 22,
songs: ["翠花", "权志龙", "vietra"],
hobby: [
{name: "小说"},
{name: "游戏"},
{name: "旅行"}
]
};
let {name, age, songs: [one, two, three], hobby: [first, second, third]} = xixi;
console.log(name);
console.log(age);
console.log(one);
console.log(two);
console.log(three);
console.log(first);
console.log(second);
console.log(third);

模板字符串

模板字符串是增强版的字符串,用反引号(``)标识,特点:
字符串中可以出现换行符
可以使用 ${xxx} 形式输出变量
当遇到字符串与变量拼接的情况使用模板字符串

变量拼接

1
2
3
let name = '西西';
let result = `欢迎${name}访问我的文章`;
console.log(result);

字符串中可以出现换行符

1
2
3
4
5
6
let str = `<ul>
<li>白云</li>
<li>太阳</li>
<li>大海</li>
</ul>`;
console.log(str);

简化对象写法

ES6 允许在大括号里面,直接写入变量和函数,作为对象的属性和方法,这样的书写更加简洁
以后用简写就对了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
let name = "西西";
let age = 22;
let speak = function () {
console.log(this.name);
};

//属性和方法简写
let person = {
name,
age,
speak
};

console.log(person.name);
console.log(person.age);
person.speak();

箭头函数

ES6 允许使用「箭头」(=>)定义函数

1
2
3
let fn = (arg1, arg2, arg3) => {
return arg1 + arg2 + arg3;
}

特点:

  • 如果形参只有一个,则小括号可以省略
  • 函数体如果只有一条语句,则花括号可以省略,函数的返回值为该条语句的执行结果
  • 箭头函数 this 指向声明时所在作用域下 this 的值,箭头函数不会更改 this 指向,用来指定回调函数会非常合适
  • 箭头函数不能作为构造函数实例化
  • 不能使用 arguments 实参
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    省略小括号的情况:
    let fn = num => {
    return num * 10;
    };
    省略花括号的情况:
    let fn = score => score * 20;
    this 指向声明时所在作用域中 this 的值
    let fn = () => {
    console.log(this);
    }
    fn();

    let school = {
    name: "张三",
    getName() {
    let subFun = () => {
    console.log(this);
    }
    subFun();
    }
    };
    school.getName();

rest 参数

用于获取函数的实参,用来代替 arguments 参数
rest参数非常适合不定个数参数函数的场景

1
2
3
4
5
6
7
8
9
10
11
12
// 作用与 arguments 类似
function add(...args) {
console.log(args);
}
add(1, 2, 3, 4, 5);

// rest 参数必须是最后一个形参
function minus(a, b, ...args) {
console.log(a, b, args);
}
minus(100, 1, 2, 3, 4, 5, 19);

spread扩展运算符…

扩展运算符(spread)也是三个点(…),好比 rest 参数的逆运算,将一个数组转为用逗号分隔的参数序列,对数组进行解包

1
2
3
4
5
6
// 展开数组
let lover = ["桃冕","松瑰","雾刃"];
function fn() {
console.log(arguments);
}
fn(...lover);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 展开对象
let skillOne = {
q: "Q技能"
};
let skillTwo = {
w: "W技能"
};
let skillThree = {
e: "E技能"
};
let skillFour = {
r: "R技能"
};
let gailun = {...skillOne, ...skillTwo, ...skillThree, ...skillFour};
console.log(gailun);

Symbol类型

遇到唯一性的场景时要想到 Symbol

Symbol的使用

ES6 引入了一种新的原始数据类型 Symbol,表示独一无二的值,它是 JavaScript 语言的第七种数据类型,是一种类似于字符串的数据类型,Symbol 特点如下:

Symbol 的值是唯一的,用来解决命名冲突的问题
Symbol 值不能与其它数据进行运算
Symbol 定义的对象属性不能使用 for…in 循环遍 历 ,但是可以使用 Reflect.ownKeys 来获取对象的所有键名

1
2
3
4
5
6
7
8
9
const a = Symbol();
console.log(a); //Symbol()

//因为Symbol是基本数据类型,而不是对象,不能 new 。
const a = new Symbol();//报错,Symbol is not a constructor

//使用Symbol()创建一个Symbol类型的值并赋值给a变量后,你就得到了一个在内存中独一无二的值。现在除了通过变量a,任何人在任何作用域内都无法重新创建出这个值
const a = Symbol();
const b = Symbol();

class类

ES6 提供了更接近传统语言的写法,引入了 Class(类)这个概念,作为对象的模板。通过 class 关键字,可以定义类。基本上,ES6 的 class 可以看作只是 一个语法糖,它的绝大部分功能,ES5 都可以做到,新的 class 写法只是让对象原型的写法更加清晰、更像面向对象编程的语法而已,它的一些如下:

class:声明类
constructor:定义构造函数初始化
extends:继承父类
super:调用父级构造方法
static:定义静态方法和属性

创建类

class 作为对象的模板被引入ES6,你可以通过 class 关键字定义类。class 的本质依然是一个函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<script>
class person {
//关键字声明方式
constructor(name) {
this.name=name
}
say() {
console.log("hello");
}
}

var p = new person('p');
p.say(); //'hello'
console.log(p.name);
</script>

类的继承

类的继承通过extends关键字实现。
子类必须在constructor中调用super()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<script>
class Person {
constructor(name, age) {
this.name = name;
this.age = age;
}
say() {
console.log(this.name + ":" + this.age);
}
}
class Student extends Person {
constructor(name, age, sex) {
super(name, age);
this.sex = sex;
}
}
var student = new Student("admin", 12, "male");
student.name; //'admin'
student.sex; //'male'
student.say(); //'ren:12'
</script>

Promise

认识Promise

Promise是ES6引入的异步编程的新解决方案,语法上Promise是一个构造函数,用来封装异步操作并可以获取其成功或失败的结果。
Promise 是处理异步操作的重要工具之一。它提供了一种更加清晰和可控的方式来处理异步代码,避免了传统的回调地狱问题,并使得错误处理更为直观。

一个 Promise 对象代表一个异步操作的最终完成(或失败),及其结果值。它的状态有三种:
Pending(进行中):初始状态,既不是成功也不是失败。
Fulfilled(已成功):操作成功完成。
Rejected(已失败):操作失败

Promise基本使用

创建Promise

通过构造函数 Promise 来创建一个新的 Promise 实例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
const myPromise = new Promise((resolve, reject) => {
// 异步操作逻辑
if (/* 操作成功 */) {
resolve('成功的结果');
} else {
reject('失败的原因');
}
});
---

const myPromise2 = new Promise((resolve, reject) => {
// 异步操作
setTimeout(() => {
const success = true; // 假设这是异步操作的结果
if (success) {
resolve("操作成功");
} else {
reject("操作失败");
}
}, 1000);
});

resolve 函数用于将 Promise 状态从 Pending 转变为 Fulfilled 并返回结果。
reject 函数用于将 Promise 状态从 Pending 转变为 Rejected 并返回原因

使用Promise

使用 .then() 方法来处理 Promise 成功的状态,.catch() 方法来处理失败的状态:

1
2
3
4
5
myPromise.then((value) => {
console.log(value); // 输出: 操作成功
}).catch((error) => {
console.error(error); // 输出: 操作失败
});

链式调用

Promise 支持链式调用,这允许你在一系列异步操作之间传递数据而不丢失上下文:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
myPromise
.then(result => {
console.log('第一步:', result);
return '下一步的数据';
})
.then(nextResult => {
console.log('第二步:', nextResult);
})
.catch(error => {
console.error('遇到错误:', error);
});
---
myPromise
.then((value) => {
console.log(value); // 处理成功的结果
return "新的值";
})
.then((newValue) => {
console.log(newValue); // 处理新的值
})
.catch((error) => {
console.error(error); // 处理失败的结果
});

Promise.all 和 Promise.race

Promise.all(iterable)

接收一个可迭代对象(如数组)作为参数,当所有 Promise 都变为 Fulfilled 时返回一个包含每个 Promise 结果的新 Promise。如果有任何一个被拒绝,则返回的 Promise 将立即拒绝

Promise.all()用于将多个 Promise 实例包装成一个新的 Promise 实例。当所有 Promise 都成功时,返回的结果是一个数组,包含每个 Promise 的结果;如果有一个 Promise 失败,则直接返回失败的结果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
const p1 = Promise.resolve(3);
const p2 = 42;
const p3 = new Promise((resolve, reject) => {
setTimeout(resolve, 100, 'foo');
});

Promise.all([p1, p2, p3]).then(values => {
console.log(values); // [3, 42, "foo"]
});
---
const promise1 = Promise.resolve(1);
const promise2 = Promise.resolve(2);
const promise3 = Promise.resolve(3);

Promise.all([promise1, promise2, promise3])
.then((values) => {
console.log(values); // 输出: [1, 2, 3]
})
.catch((error) => {
console.error(error);
});

Promise.race(iterable)

接收一个可迭代对象作为参数,返回一个新的 Promise,该 Promise 在传入的任意一个 Promise 变为 Fulfilled 或 Rejected 时立即改变其状态并采用那个 Promise 的值或理由

Promise.race()用于将多个 Promise 实例包装成一个新的 Promise 实例。它会在第一个 Promise 完成或失败时立即返回结果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
const p1 = new Promise((resolve, reject) => {
setTimeout(resolve, 500, 'one');
});
const p2 = new Promise((resolve, reject) => {
setTimeout(resolve, 100, 'two');
});

Promise.race([p1, p2]).then(value => {
console.log(value); // "two"
});
---
const promise1 = new Promise((resolve) => setTimeout(resolve, 1000, 'one'));
const promise2 = new Promise((resolve) => setTimeout(resolve, 2000, 'two'));

Promise.race([promise1, promise2])
.then((value) => {
console.log(value); // 输出: one
})
.catch((error) => {
console.error(error);
});

例子

异步数据获取

假设你需要从一个API获取数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
const fetchData = () => {
return new Promise((resolve, reject) => {
fetch('https://api.example.com/data')
.then(response => response.json())
.then(data => resolve(data))
.catch(error => reject(error));
});
};

fetchData()
.then(data => {
console.log(data); // 处理获取的数据
})
.catch(error => {
console.error(error); // 处理错误
});

链式调用

假设你需要先获取用户数据,然后根据用户数据获取其他信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
const getUserData = () => {
return new Promise((resolve, reject) => {
fetch('https://api.example.com/user')
.then(response => response.json())
.then(data => resolve(data))
.catch(error => reject(error));
});
};

const getOtherInfo = (userId) => {
return new Promise((resolve, reject) => {
fetch(`https://api.example.com/other/${userId}`)
.then(response => response.json())
.then(data => resolve(data))
.catch(error => reject(error));
});
};

getUserData()
.then(user => {
console.log(user); // 处理用户数据
return getOtherInfo(user.id);
})
.then(otherInfo => {
console.log(otherInfo); // 处理其他信息
})
.catch(error => {
console.error(error); // 处理错误
});