ES6---ES11 新特性

发布于:2025-08-30 ⋅ 阅读:(20) ⋅ 点赞:(0)

这是一篇笔记, 原视频:
【尚硅谷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)

  • 简写规则:

    1. 省略小括号: 只有一个参数时可以省略小括号
    2. 省略 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);
}

工作原理:

  1. 创建一个指针对象, 指向当前 数据结构的起始位置
  2. 第一次调用对象的 next()方法, 指针自动指向数据结构的第一个成员
  3. 接下来不断调用 next 方法, 指针一直往后移动, 直到指向最后一个成员
  4. 每调用 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
}

自定义迭代器的步骤:

  1. 定义Symbol.iterator方法, 返回一个包含 next()方法的对象
  2. 在 next()方法中, 定义遍历规则, 返回一个包含 value 和 done 属性的对象
  3. 其中遍历未完成时, 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>

使用工具来提升不同浏览器的兼容性

  1. 安装工具 babel-cli babel-preset-env browserify(webpack)
  2. babel 转换(文件夹也行)
    npx babel app.js -o app-compiled.js --presets=babel-preset-env
  3. 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 函数

  1. 返回值为 promise 对象
  2. 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 关键字

  1. await 关键字只能在 async 函数中使用
  2. await 右侧的表达式一般为 promise 对象
  3. await 返回 的是 promise 成功的值
  4. 如果 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. 参数默认是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环境下