ES6引入了许多新的语法用过很多了,但是总没有区分开,哪些是es6新加的,最近面试有问到,所以这里整理一下,算是比较全的,这里只涉及到了语法相关的
一、箭头函数:
- 使用箭头函数可以更简洁地定义函数,并且在函数体内的
this
绑定更符合直觉 - 如果箭头函数体内只有一个表达式,无需使用 return 关键字,传参只有一个,也可以省略()。
- 箭头函数的上下文(this 的值)在定义时就已经确定,并且无法通过 call、apply、bind 来改变
- 不能作为构造函数使用,不能通过 new 关键字实例化,否则会抛出错误。
- 箭头函数没有自己的 arguments 对象,它会继承外围函数的 arguments 对象(如果有的话)。
// 传统函数
function add(a, b) {
return a + b;
}
// 箭头函数
const add = (a, b) => a + b;
二、解构赋值:
解构赋值使得从数据结构中提取和使用值变得更加简洁和方便,同时提高了代码的可读性。
(一)使用方法
- 可以从数组或对象中提取值,并赋给变量。
// 数组解构
const [a, b] = [1, 2];
// 对象解构
const { name, age } = { name: 'John', age: 30 };
- 函数参数解构:
function printPersonInfo({ name, age }) {
console.log(`Name: ${name}, Age: ${age}`);
}
const person = { name: 'John', age: 30 };
printPersonInfo(person); // 输出 Name: John, Age: 30
- 嵌套解构:
const person = {
name: 'John',
age: 30,
address: {
city: 'New York',
zip: '10001'
}
};
const { name, address: { city, zip } } = person;
//注意这里的addres是不能解出的
console.log(name, city, zip); // 输出 John New York 10001
(二)常用场景:
- 交换变量的值:
let a = 1, b = 2;
[a, b] = [b, a];
console.log(a, b); // 输出 2 1
- 提取函数返回的对象的值:
function getPerson() {
return { name: 'John', age: 30 };
}
const { name, age } = getPerson();
console.log(name, age); // 输出 John 30
- 从正则表达式匹配中提取值:
const url = 'https://example.com/user/123';
const [, , userID] = url.match(/\/user\/(\d+)/);
console.log(userID); // 输出 123
三、let 和 const:
(一)作用域:
let 声明的变量具有块级作用域,即变量在 {} 内部声明的话,只在该块内部可见
const 声明的变量同样具有块级作用域
(二)变量重新赋值
let 声明的变量可以被重新赋值。
const 声明的变量必须进行初始化,并且不能被重新赋值。一旦赋值,就不能再次更改。
(三)变量提升
let 和 const不会进行变量提升(hoisting),变量在声明之前是不可用的。
(四)全局对象属性
在全局作用域中使用 let 声明的变量不会成为全局对象的属性。
与 let 不同,const 在全局作用域中声明的变量会成为全局对象的属性。
const pi = 3.14;
// pi = 3.14159; // 错误:Assignment to constant variable.
console.log(pi); //输出 3.14
if (true) {
let x = 10;
console.log(x); // 输出 10
const y = 20;
console.log(y); // 输出 20
}
// console.log(x); // 错误:x is not defined
// console.log(y); // 错误:y is not defined
四、模板字符串:
- 使用
${}
创建多行字符串,可以插入变量。 - 允许直接换行
- 模板字符串中还可以包含任意的 JavaScript 表达式
- 模板字符串可以嵌套在其他模板字符串中
const name = 'John';
const greeting = `Hello, ${name}!`;
五、默认参数值:
- 可以为函数参数设置默认值,默认值可以使常量,也可以是表达式。
function greet(name = 'Guest') {
console.log(`Hello, ${name}!`);
}
六、展开运算符(Spread Operator):
(一)展开数组:
1.基本用法:
const arr1 = [1, 2, 3];
const arr2 = [...arr1, 4, 5];
console.log(arr2); // 输出: [1, 2, 3, 4, 5]
2.复制数组–浅拷贝:
const originalArray = [1, 2, 3];
const copiedArray = [...originalArray];
console.log(copiedArray); // 输出: [1, 2, 3]
console.log(originalArray === copiedArray); // 输出: false,两个数组是独立的
3.合并数组–浅拷贝:
const arr1 = [1, 2, 3];
const arr2 = [4, 5, 6];
const mergedArray = [...arr1, ...arr2];
console.log(mergedArray); // 输出: [1, 2, 3, 4, 5, 6]
(二)展开对象:
1.基本用法:
const obj1 = { a: 1, b: 2 };
const obj2 = { ...obj1, c: 3, d: 4 };
console.log(obj2); // 输出: { a: 1, b: 2, c: 3, d: 4 }
2.复制对象–浅拷贝
const originalObject = { x: 1, y: 2 };
const copiedObject = { ...originalObject };
console.log(copiedObject); // 输出: { x: 1, y: 2 }
console.log(originalObject === copiedObject); // 输出: false,两个对象是独立的
(三)函数调用中的应用:
将数组作为参数:
function sum(a, b, c) {
return a + b + c;
}
const numbers = [1, 2, 3];
const result = sum(...numbers);
console.log(result); // 输出: 6
(四)字符串展开:
const str = 'hello';
const letters = [...str];
console.log(letters); // 输出: ['h', 'e', 'l', 'l', 'o']
(五)与 rest 参数结合:
展开运算符可以与 rest 参数结合使用,以更灵活地处理函数的参数。
function example(...args) {
console.log(args);
}
const numbers = [1, 2, 3, 4, 5];
example(...numbers); // 输出: [1, 2, 3, 4, 5]
七、Rest 参数:
(一)基本用法:
function sum(...numbers) {
return numbers.reduce((acc, num) => acc + num, 0);
}
console.log(sum(1, 2, 3, 4, 5)); // 输出: 15
…numbers 表示将传递给 sum 函数的所有参数收集到一个名为 numbers 的数组中。
(二)与其他参数结合使用:
Rest 参数可以与其他参数一同使用,但要注意 Rest 参数必须是最后一个参数。
function example(a, b, ...rest) {
console.log(a, b, rest);
}
example(1, 2, 3, 4, 5); // 输出: 1 2 [3, 4, 5]
(三)Rest 参数的默认值:
Rest 参数可以设置默认值,就像普通参数一样。
function example(a, b, ...rest = []) {
console.log(a, b, rest);
}
example(1, 2, 3, 4, 5); // 输出: 1 2 [3, 4, 5]
example(1, 2); // 输出: 1 2 []
(四)Rest 参数与解构赋值结合:
Rest 参数可以与解构赋值结合使用,以便更灵活地处理参数。
function example({ a, b, ...rest }) {
console.log(a, b, rest);
}
example({ a: 1, b: 2, c: 3, d: 4 }); // 输出: 1 2 { c: 3, d: 4 }
八、Promise:
特点:
1、处理异步操作;
2、避免了回调地狱(Callback Hell)和层层嵌套的问题;
(一)Promise 的基本结构:
const myPromise = new Promise((resolve, reject) => {
// 异步操作,比如从服务器获取数据
// 如果操作成功,调用 resolve 并传递结果
resolve(result);
// 如果操作失败,调用 reject 并传递错误信息
// reject(error);
});
myPromise
.then(result => {
// 处理成功的结果
})
.catch(error => {
// 处理失败的情况
});
(二)状态(State):
Pending
(进行中): 初始状态,即操作尚未完成,也没有失败。Fulfilled
(已成功): 操作成功完成。Rejected
(已失败): 操作失败。
(三)then
方法:
then
方法用于处理 Promise
对象的成功状态,接收一个回调函数,该回调函数在 Promise
状态变为成功时被调用。
myPromise
.then(result => {
// 处理成功的结果
})
.catch(error => {
// 处理失败的情况
});
(四)catch
方法:
catch
方法用于处理 Promise
对象的失败状态,接收一个回调函数,该回调函数在 Promise
状态变为失败时被调用。
myPromise
.then(result => {
// 处理成功的结果
})
.catch(error => {
// 处理失败的情况
});
(五)finally
方法:
finally
方法用于在 Promise
对象的状态变为成功或失败时执行某些操作,无论最终结果是什么都被调用。
myPromise
.then(result => {
// 处理成功的结果
})
.catch(error => {
// 处理失败的情况
})
.finally(() => {
// 无论成功或失败都会执行的操作
});
(六)链式调用:
then
和 catch
方法可以链式调用,使代码更加清晰。
myPromise
.then(result => {
// 处理成功的结果
return anotherPromise;
})
.then(anotherResult => {
// 处理另一个异步操作的成功结果
})
.catch(error => {
// 处理失败的情况
});
(七)Promise.all
:
Promise.all
方法用于等待多个 Promise
对象全部完成,然后返回一个包含所有结果的数组,如果其中任何一个 Promise
失败,则整个操作失败。
const promises = [promise1, promise2, promise3];
Promise.all(promises)
.then(results => {
// 处理所有成功的结果
})
.catch(error => {
// 处理失败的情况
});
(八)Promise.race
:
Promise.race
方法用于等待多个 Promise
对象中的任何一个完成,然后返回第一个完成的结果,无论是成功还是失败。
const promises = [promise1, promise2, promise3];
Promise.race(promises)
.then(result => {
// 处理第一个完成的成功结果
})
.catch(error => {
// 处理第一个完成的失败情况
});
(九)创建已解决或已拒绝的 Promise:
有时候,我们希望立即创建一个已解决(fulfilled)或已拒绝(rejected)的 Promise
对象,可以使用 Promise.resolve
和 Promise.reject
。
const resolvedPromise = Promise.resolve('Resolved value');
const rejectedPromise = Promise.reject('Rejected reason');
九、类和继承:
(一)类的基本语法:
使用 class
关键字可以声明一个类。类可以包含构造函数和类方法。
class Animal {
// 构造函数
constructor(name) {
this.name = name;
}
// 类方法
sayName() {
console.log(`My name is ${this.name}`);
}
}
// 创建类的实例
const cat = new Animal('Fluffy');
cat.sayName(); // 输出: My name is Fluffy
(二)构造函数和实例属性:
构造函数通过 constructor
方法定义,实例属性直接在构造函数中用 this
关键字声明。
class Person {
constructor(name, age) {
this.name = name;
this.age = age;
}
sayHello() {
console.log(`Hello, my name is ${this.name} and I am ${this.age} years old.`);
}
}
const john = new Person('John', 30);
john.sayHello(); // 输出: Hello, my name is John and I am 30 years old.
(三)类方法:
类方法是在类的原型上定义的,可以通过实例调用。
class Rectangle {
constructor(width, height) {
this.width = width;
this.height = height;
}
// 类方法
calculateArea() {
return this.width * this.height;
}
}
const rectangle = new Rectangle(5, 10);
console.log(rectangle.calculateArea()); // 输出: 50
(四)继承:
使用 extends
关键字可以实现类的继承。子类可以通过 super
关键字调用父类的构造函数和方法。
class Dog extends Animal {
// 子类构造函数
constructor(name, breed) {
// 调用父类构造函数
super(name);
this.breed = breed;
}
// 子类方法
bark() {
console.log('Woof, woof!');
}
// 覆盖父类方法
sayName() {
console.log(`My name is ${this.name} and I am a ${this.breed}`);
}
}
const dog = new Dog('Buddy', 'Golden Retriever');
dog.sayName(); // 输出: My name is Buddy and I am a Golden Retriever
dog.bark(); // 输出: Woof, woof!
(五)静态方法:
使用 static
关键字可以定义类的静态方法,静态方法是类的方法而不是实例的方法,可以直接通过类名调用。
class MathUtils {
static add(x, y) {
return x + y;
}
static subtract(x, y) {
return x - y;
}
}
console.log(MathUtils.add(5, 3)); // 输出: 8
console.log(MathUtils.subtract(5, 3)); // 输出: 2
(六)getter 和 setter:
可以使用 get
和 set
关键字定义类的 getter 和 setter 方法。
class Circle {
constructor(radius) {
this._radius = radius; // 使用下划线约定表示私有属性
}
get radius() {
return this._radius;
}
set radius(value) {
if (value < 0) {
throw new Error('Radius cannot be negative');
}
this._radius = value;
}
get area() {
return Math.PI * this._radius ** 2;
}
}
const circle = new Circle(5);
console.log(circle.radius); // 输出: 5
circle.radius = 7;
console.log(circle.area); // 输出: 153.93804002589985
(七)类的继承与构造函数的继承对比:
与构造函数的继承相比,ES6 中的类的继承更为直观和易读。它引入了更多面向对象编程的概念,提供了更丰富的语法糖。
// 构造函数的继承
function Animal(name) {
this.name = name;
}
Animal.prototype.sayName = function() {
console.log(`My name is ${this.name}`);
};
function Dog(name, breed) {
Animal.call(this, name);
this.breed = breed;
}
Dog.prototype = Object.create(Animal.prototype);
Dog.prototype.constructor = Dog;
Dog.prototype.bark = function() {
console.log('Woof, woof!');
};
// ES6 类的继承
class Animal {
constructor(name) {
this.name = name;
}
sayName() {
console.log(`My name is ${this.name}`);
}
}
class Dog extends Animal {
constructor(name, breed) {
super(name);
this.breed = breed;
}
bark() {
console.log('Woof, woof!');
}
}
十、模块化(import 和 export):
模块化是一种将程序拆分为独立、可维护的模块的编程范式。在 JavaScript 中,模块化的实现主要依赖于 import
和 export
语法。
(一)导出(Export):
在模块中,可以使用 export
关键字将变量、函数、类或其他代码导出,使其在其他模块中可用。
导出变量:
// math.js
export const pi = 3.14;
export const square = x => x * x;
导出函数:
// utils.js
export function add(a, b) {
return a + b;
}
export function subtract(a, b) {
return a - b;
}
导出类:
// shapes.js
export class Circle {
constructor(radius) {
this.radius = radius;
}
area() {
return Math.PI * this.radius ** 2;
}
}
导出默认值:
// main.js
const message = 'Hello, world!';
export default message;
(二)导入(Import):
在其他模块中,可以使用 import
关键字导入导出的变量、函数、类或默认值。
导入具名导出:
// main.js
import { pi, square } from './math';
console.log(pi); // 输出: 3.14
console.log(square(5)); // 输出: 25
导入所有导出:
// main.js
import * as math from './math';
console.log(math.pi); // 输出: 3.14
console.log(math.square(5)); // 输出: 25
导入默认值:
// main.js
import message from './main';
console.log(message); // 输出: Hello, world!
重命名导入:
// main.js
import { pi as circlePi, square as squareFn } from './math';
console.log(circlePi); // 输出: 3.14
console.log(squareFn(5)); // 输出: 25
(三)模块的相对路径:
模块的路径可以是相对路径或绝对路径,相对路径是相对于当前模块的文件路径。
// main.js
import { pi } from './utils/math';
console.log(pi); // 输出: 3.14
(四)导入导出的综合例子:
// math.js
export const pi = 3.14;
export function square(x) {
return x * x;
}
// shapes.js
export class Circle {
constructor(radius) {
this.radius = radius;
}
area() {
return Math.PI * this.radius ** 2;
}
}
// main.js
import { pi, square } from './math';
import { Circle } from './shapes';
console.log(pi); // 输出: 3.14
console.log(square(5)); // 输出: 25
const myCircle = new Circle(3);
console.log(myCircle.area()); // 输出: 28.26
(五)动态导入:
ES6 还引入了动态导入,可以在运行时根据条件来决定加载哪个模块。
const moduleName = 'math';
import(moduleName)
.then(mathModule => {
console.log(mathModule.pi);
})
.catch(error => {
console.error('Failed to load module:', error);
});
总结:复习一遍后,感觉大部分还是有经常用到的,也确实忘掉了一些,感觉又可以了,冲冲冲!!