这是一篇笔记, 原视频:
【尚硅谷Web前端ES6教程,涵盖ES6-ES11】 https://www.bilibili.com/video/BV1uK411H7on/?share_source=copy_web&vd_source=7336f6dae330ae9637a6a01932103639
let 声明
let a; // 单个声明
let b, c, d; // 多个声明
let e = 10; // 单个声明并赋值
let f = 10,
g = "hello",
h = [1, 3, 5],
i = true; // 多个声明并赋值
注意事项:
- 变量不能重复声明
- 有块级作用域(全局, 函数, eval)
- 不存在变量提升
- 不影响作用域链
{
let a = 10;
function f() {
console.log(a); // 10
}
f(); // 输出10
}
const 声明
const PI = 3.1415926; // 常量声明
注意事项:
- 一定要赋初始值
- 一般声明使用大写
- 常量的值不能修改
- let 的注意事项
解构赋值
// 数组
const arr = [1, 2, 3];
const [a, b, c] = arr; // 解构赋值
console.log(a, b, c); // 1 2 3
// 对象
const Student = {
name: "Tom",
age: 20,
gender: "male",
Introduce: function () {
console.log(
`My name is ${this.name}, I am ${this.age} years old, I am ${this.gender}.`
); // 注意this
},
};
let { name, age, gender, Introduce } = Student; //方法频繁调用, 可使用解构赋值, 属性名要对应相同
Introduce(); // My name is Tom, I am 20 years old, I am male.
let { name: myName, age: myAge, gender: myGender } = Student; // 别名
console.log(myName, myAge, myGender); // Tom 20 male
模版字符串(``)
let str = `<ul>
<li>item1</li>
<li>item2</li>
</ul>`; // 可以出现换行符
let name = "Tom";
let sayHello = `Hello, ${name}!`; // 使用模版字符串拼接字符串
对象的简化写法
let name = "Tom";
let age = 20;
let obj = {
name, // 等同于 name: name
age,
sayHello() {
console.log(`Hello, ${this.name}!`);
},
}; // 简化写法
箭头函数(=>
)
// 传统函数
let add = function (a, b) {
return a + b;
};
// 箭头函数
let addNew = (a, b) => {
return a + b;
};
// 箭头函数可以省略return关键字
let addNew2 = (a, b) => a + b; // 等同于 addNew, 只有一行代码时可以省略{}
注意事项:
- this 是静态的, this 始终指向函数声明时所在作用域下的 this 的值, 也不能使用 call, apply, bind 方法改变 this 的指向
// 示例
function getName() {
console.log(this.name);
}
let getNameNew = () => {
console.log(this.name);
};
window.name = "window";
let obj = {
name: "Tom",
};
getName(); // window
getNameNew(); // window
getName.call(obj); // Tom
getNameNew.call(obj); // window, 因为在window作用域下声明
不能作为构造函数实例化对象
不能使用 arguments 变量(…args)
简写规则:
- 省略小括号: 只有一个参数时可以省略小括号
- 省略 return 关键字和{}: 只有一行代码时可以省略 return 关键字
箭头函数适合与 this 无关的回调, 如定时器, 数组的方法回调
不适合与 this 有关的回调, 如事件监听(回调), 对象的方法
函数参数默认值
function add(a, b = 10) {
return a + b;
} // 具有默认值的参数, 最好放到最后
console.log(add(1)); // 11
// 与解构赋值相结合
const connect = {
host: "localhost",
user: "root",
password: "123456",
port: 3306,
};
function connectDB({ host = "127.0.0.1", user, password, port }) {
console.log(`Connect to ${host}:${port} with ${user}:${password}`);
}
rest 参数
function add(...args) {
// 数组, 增加了对数据的处理
let sum = 0;
for (let i = 0; i < args.length; i++) {
sum += args[i];
}
return sum;
}
console.log(add(1, 2, 3, 4, 5)); // 15
注意事项: 只能作为最后一个参数
扩展运算符
… 运算符能将数组转换为逗号分隔的参数序列
//1. 数组的合并
const odds = [1, 3, 5];
const evens = [2, 4, 6];
// const all = odds.concat(evens); ES5
const all = [...odds,...evens]; // [1, 3, 5, 2, 4, 6]
//2. 数组的克隆(浅拷贝)
cosnt strArr = ["hello", "world"];
const newArr = [...strArr]; // ["hello", "world"]
// 3. 将伪数组转换为数组
const divs = document.querySelectorAll("div");
const arr = [...divs]; // [div, div, div]
Symbol 数据类型
引入的一种新的数据类型, 表示独一无二的值, 是一种类似于字符串的数据类型
特点:
- 值是唯一的, 用来解决 命名 冲突的问题
- 不能与其他数据进行 运算
- 定义的对象属性不能 使用 for…in 循环遍历, 但可以使用 Reflect.ownKeys()方法获取对象的所有键名
// 创建 Symbol
let s1 = Symbol(); // 自动生成唯一的 Symbol 值
let s2 = Symbol("name"); // 带有描述的 Symbol 值
let s3 = Symbol("name"); // 与 s2 不同的值
let s4 = Symbol.for("name"); // 全局 Symbol 值, 与其他 Symbol 值不同
let s5 = Symbol.for("name"); // 与 s4 相同的值
// 需求: 向对象添加方法, 关于 up, down
let game = {
name: "game",
up() {
console.log("up");
},
down() {
console.log("down");
},
};
let methods = {
up: Symbol(),
down: Symbol(),
};
game[methods.up] = function () {
console.log("I am up");
};
game[methods.down] = function () {
console.log("I am down");
};
// 调用方法
game[methods.up](); // I am up
game["up"](); // up
// 创建对象时添加
let game = {
name: "game",
[Symbol("up")]() {
console.log("I am up");
},
};
迭代器
Iterator 是一种接口, 为各种不同的数据结构提供统一的访问机制
ES6 创造了一种新的遍历命令, for…of
原生具备 Iterator 接口的数据结构: Array, Map, Set, String, TypedArray, 函数的 arguments 对象, NodeList 对象
const arr = [1, 2, 3];
for (let value of arr) {
console.log(value);
}
工作原理:
- 创建一个指针对象, 指向当前 数据结构的起始位置
- 第一次调用对象的 next()方法, 指针自动指向数据结构的第一个成员
- 接下来不断调用 next 方法, 指针一直往后移动, 直到指向最后一个成员
- 每调用 next 方法返回一个包含 value 和 done 属性的对象
需要 自定义遍历数据的时候, 要想到迭代器
// 使用 for...of 遍历数组, 并返回 姓名
const StuClass = {
name: "一班",
stus: ["Tom", "Jerry", "Lucy"],
[Symbol.iterator]() {
let index = 0;
return {
next: () => {
if (index < this.stus.length) {
const res = { value: this.stus[index], done: false };
index++;
return res;
} else {
return { value: undefined, done: true };
}
},
};
},
};
for (let name of StuClass) {
console.log(name); // Tom Jerry Lucy
}
自定义迭代器的步骤:
- 定义Symbol.iterator方法, 返回一个包含 next()方法的对象
- 在 next()方法中, 定义遍历规则, 返回一个包含 value 和 done 属性的对象
- 其中遍历未完成时, done 属性值为 false, 遍历完成时, done 属性值为 true, 且 value 属性值为 undefined
生成器函数
是一个特殊的函数
- 声明时使用 function* 关键字
- 内部可使用 yield 关键字, 将函数暂停, 使用 next()方法进行到下一模块
function* gen() {
console.log("start");
yield 1;
console.log("continue");
yield 2;
console.log("end");
}
let g = gen();
g.next(); // start
g.next(); // continue
g.next(); // end
for (let value of gen()) {
console.log(value);
} // 1 2 , 使用for...of遍历时, 输出 yield 后面的语句
参数:
- 可以接收外部的参数, next()方法也可以传递参数
- 第二个 next()方法的参数为 第一个 yield 的"返回值"
function* gen(x) {
console.log(x);
let one = yield "first";
console.log(one);
}
let g = gen(10);
g.next(); // 10
g.next("hello"); // hello
// 需求 1s后控制台输出 111, 2s后输出 222, 3s后输出 333
function one() {
setTimeout(() => {
console.log("111");
iterator.next();
}, 1000);
}
function two() {
setTimeout(() => {
console.log("222");
iterator.next();
}, 2000);
}
function three() {
setTimeout(() => {
console.log("333");
}, 3000);
}
function* gen() {
yield one();
yield two();
yield three();
}
let iterator = gen();
iterator.next();
// 模拟获取 用户数据 订单数据 商品数据, 按照顺序每一秒后获得, 并在生成器函数中打印
function getUsers() {
setTimeout(() => {
let data = "用户数据";
iterator.next(data);
}, 1000);
}
function getOrders() {
setTimeout(() => {
let data = "订单数据";
iterator.next(data);
}, 1000);
}
function getGoods() {
setTimeout(() => {
let data = "商品数据";
iterator.next(data);
}, 1000);
}
function* gen() {
let users = yield getUsers();
console.log(users);
let orders = yield getOrders();
console.log(orders);
let goods = yield getGoods();
console.log(goods);
}
let iterator = gen();
iterator.next();
集合(set)
let set0 = new Set();
let set = new Set([1, 2, 3, 2, 1]); // 去重
// 元素个数
console.log(set.size);
// 添加元素
set.add(4);
// 删除元素
set.delete(2);
// 判断元素是否存在
set.has(2); // false
// 清空集合
set.clear();
// 遍历集合
for (let value of set) {
} // 实现了 Iterator 接口
// 集合的应用
const arr = [1, 2, 3, 2, 1];
// 数组去重
const uniqueArr = [...new Set(arr)];
console.log(uniqueArr); // [1, 2, 3]
// 数组求交集
let arr2 = [2, 3, 4];
let arr3 = [3, 4, 5];
let res = [...new Set(arr2)].filter((value) => arr3.includes(value));
console.log(res); // [3, 4]
// 数组求并集
let unionArr = [...new Set([...arr2, ...arr3])];
// 数组求差集
let diffArr = [...new Set(arr2)].filter((value) => !arr3.includes(value)); //交集取反
映射(map)
let map = new Map();
map.set("name", "Tom"); // 添加键值对, key 可以是任意类型
map.get("name"); // 获取值
map.has("name"); // 判断是否存在
map.delete("name"); // 删除键值对
map.clear(); // 清空
使用 for…of 遍历时返回多个数组, 每个数组内第一个元素是键, 第二个元素是值
类(class)
class Person {
constructor(name, age) {
this.name = name;
this.age = age;
} // 构造函数
sayHello() {
console.log(`Hello, my name is ${this.name}, I am ${this.age} years old.`);
} // 实例方法
}
class Phone {
static name = "手机"; // 静态属性
static getName() {
// 静态方法
return this.name;
}
}
// 只有类可以调用 静态方法和静态成员变量, 实例化对象不能调用
class Student extends Person {
constructor(name, age, grade) {
super(name, age);
this.grade = grade;
}
}
// 也可以对父类方法进行重写, 但重写方法内部不能调用父类的同名方法
// 也有get 和 set方法, 用于对属性的读写控制
数值扩展
// Number.EPSILON: 2.220446049250313e-16 是 JavaScript 能表示的最小的正浮点数
function isEqual(a, b) {
if(Math.abs(a - b) < Number.EPSILON){
return true;
}else{
return false;
}
} // 判断两个浮点数是否相等
let b = 0b101; // 二进制
let o = 0o77; // 八进制
let h = 0x1F; // 十六进制
// Number.isFinite() 判断是否为有限数
console.log(Number.isFinite(10)); // true
console.log(Number.isFinite(Infinity)); // false
// Number.isNaN() 判断是否为 NaN
console.log(Number.isNaN(NaN)); // true
// Number.ParseInt() 解析整数 Number.parseFloat() 解析浮点数
console.log(Number.parseInt("123沙发上")); // 123
console.log(Number.parseFloat("123.456沙发上")); // 123.456
// Number.isInteger() 判断是否为整数
console.log(Number.isInteger(10)); // true
console.log(Number.isInteger(10.1)); // false
// Math.trunc() 截取整数部分
console.log(Math.trunc(10.1)); // 10
// Math.sign() 符号函数, 返回数值的正负号
console.log(Math.sign(-5)); // -1
console.log(Math.sign(0)); // 0
console.log(Math.sign(5)); // 1
对象方法的扩展
// Object.is() 判断两个值是否相同
console.log(Object.is(0, -0)); // false
console.log(Object.is(NaN, NaN)); // true 注: NaN !== NaN
// Object.assign() 用于对象的合并
// 第一个参数是目标对象, 后面的参数是源对象
let obj1 = { a: 1, b: 2 };
let obj2 = { b: 3, c: 4 };
let obj3 = Object.assign(obj1, obj2);
console.log(obj3); // {a: 1, b: 3, c: 4}
// Object.setPrototypeOf() 设置原型对象
模块化
优势: 代码复用, 命名空间隔离, 提高代码可读性、可维护性
// 分别暴露
export let school = "北京大学";
export function saySchool() {
console.log("这是北京大学");
}
// 统一暴露
// export {
// school,
// saySchool,
// }
// }
// export default {
// school: "清华大学",
// saySchool() {
// console.log("这是清华大学");
// }
// }
<script type="module">
import * as schoolModule from "./school.js";
console.log(schoolModule.school); // 北京大学
console.log(schoolModule.default.school) // 清华大学
</script>
<script type="module">
import {school, saySchool} from "./school.js";
import {school as school2, saySchool as saySchool2} from "./school2.js";
// 重名时, 可以使用别名, 加 as 关键字, 引入default时, 必须使用 as 关键字
</script>
一般在入口文件 app.js 中引入其他模块
<script type="module" src="./app.js">
</script>
使用工具来提升不同浏览器的兼容性
- 安装工具 babel-cli babel-preset-env browserify(webpack)
- babel 转换(文件夹也行)
npx babel app.js -o app-compiled.js --presets=babel-preset-env - browserify 打包
npx browserify app.js -o bundle.js
ES7新特性
// Array.prototype.includes
// 用来判断数组是否包含某个元素,返回布尔值
let arr = [1, 2, 3, 4, 5];
console.log(arr.includes(3)); // true
console.log(arr.includes(6)); // false
// ** 运算符 相当于Math.pow()
async/await
async 函数
- 返回值为 promise 对象
- promise 对象的结果由 async 函数的返回值决定
async function myFunc() {
return 1; // 函数内部的return只要不是promise对象,返回的promise对象就直接resolve(成功)
throw new Error('出错了'); // 若函数内部抛出错误, 则reject(失败), 返回一个失败的promise对象
return new Promise((resolve, reject) => {
resolve(1);
}); // 若函数内部返回一个promise对象, 则resolve(成功), 返回一个成功的promise对象, 成功的值就是函数内部resolve的参数的值, 1
}
console.log(myFunc()); // Promise {<resolved>: 1}
await 关键字
- await 关键字只能在 async 函数中使用
- await 右侧的表达式一般为 promise 对象
- await 返回 的是 promise 成功的值
- 如果 promise 失败, 则会抛出异常, 需要通过 try…catch 捕获异常
对象方法的扩展
const school = {
name: 'xxx',
cities: ['北京', '上海', '广州'],
classes: ['语文', '数学', '英语'],
}
// 获取对象所有的键
console.log(Object.keys(school)); // ['name', 'cities', 'classes']
// 获取对象所有的值
console.log(Object.values(school)); // ['xxx', ['北京', '上海', '广州'], ['语文', '数学', '英语']]
// 获取对象所有键值对
console.log(Object.entries(school)); // [['name', 'xxx'], ['cities', ['北京', '上海', '广州']], ['classes', ['语文', '数学', '英语']]]
const m = new Map(Object.entries(school)); // 转换为 Map 对象
console.log(Object.getOwnPropertyDescriptors(school)); //获取对象 属性的描述
对象展开
// function connect({host, port, username, password}){
// console.log(host);
// console.log(port);
// console.log(username);
// console.log(password);
// }
function connect({ host, port, ...user }) {
console.log(host);
console.log(port);
console.log(user);
}
connect({
host: "localhost",
port: 8080,
username: "admin",
password: "123456",
});
const one = {
a: 1
}
cosnt two = {
b: 2
}
const three = {
c: 3
}
const merged = {...one, ...two, ...three}
console.log(merged); //{a: 1, b: 2, c: 3}
正则: 命名捕获分组
let str = "<a href='http://www.baidu.com'>百度</a>"
const reg = /<a href="(?<url>.*?)">(?<text>.*?)</a>/;
const res = reg.exec(str);
console.log(res.groups.url); // http://www.baidu.com
console.log(res.groups.text); // 百度
正则: 反向断言
// 提取555
let str = "JS12319534可可来说555啦啦啦";
// 正向断言
const reg = /\d+(?=啦)/;
const res = reg.exec(str);
// 反向断言
const reg2 = /(?<=说)\d)/;
const res2 = reg2.exec(str);
Object.fromEntries()
将一个二维数组或者 Map 转换成一个对象。
const entries = [
["name", "John"],
["age", 30],
["city", "New York"],
];
const obj = Object.fromEntries(entries);
console.log(obj); // { name: 'John', age: 30, city: 'New York' }
// Object.entries(), can be used to convert an object to an array of key-value pairs.
trimStart() and trimEnd()
前者负责清除字符串左侧的空白, 后置负责清除尾部的空白
flat 与 flatMap
- flat() 方法会按照一个可迭代对象的结构展平一个数组,即将嵌套的数组展平为一个一维数组。
- 参数默认是1, 表示只展平一层, 参数为展开的深度
- flatMap() 方法与 flat() 方法类似,但它会将数组中的每一个元素都先进行映射操作,然后再展平。
私有属性
class Person {
#name;
#age;
constructor(name, age) {
this.#name = name;
this.#age = age;
}
get name() {
return this.#name;
}
get age() {
return this.#age;
}
set age(newAge) {
if (newAge > 0 && newAge < 150) {
this.#age = newAge;
} else {
console.log("年龄不合法");
}
}
set name(newName) {
this.#name = newName;
}
}
// 类似于java中的private关键字,在属性名前面加上#符号,则该属性只能在类的内部访问。
promise.allSettled([promise, promise, promise])
这个方法返回一个 promise,当所有 promises 都被 resolve 或 reject 时,返回一个数组,每个 promise 的状态都标记为 fulfilled 或 rejected。
promise.all 是必须每个结果都成功, 才能往下走
String.prototype.matchAll()
用于正则匹配中字符串的批量提取
可选链操作符(?.)
function main(config){
const dbHonst = config?.db?.host; // 等同于 config && config.db && config.db.host
console.log(dbHonst);
}
main({
db: {
host: "192.168.1.1",
user: "root"
}
cache: {
host: "192.168.1.2",
user: "root"
}
})
动态import
function main(){
import("./module.js").then(module => {}) // 动态导入模块, 返回结果为promise对象
}
BigInt
let bigInt = 12345678901234567890n;
BigInt(124); // 124n
globalThis
// 始终指向全局对象, 无论在浏览器还是在node环境下