Appearance
ES6+ 新特性面试题
1. let 和 const
问题:let 和 const 与 var 有什么区别?
答案:
主要区别:
| 特性 | var | let | const |
|---|---|---|---|
| 作用域 | 函数作用域 | 块级作用域 | 块级作用域 |
| 变量提升 | 是 | 否(暂时性死区) | 否(暂时性死区) |
| 重复声明 | 允许 | 不允许 | 不允许 |
| 重新赋值 | 允许 | 允许 | 不允许 |
示例:
javascript
// var - 函数作用域
function testVar() {
if (true) {
var x = 10;
}
console.log(x); // 10
}
// let - 块级作用域
function testLet() {
if (true) {
let y = 20;
}
console.log(y); // ReferenceError
}
// const - 不可重新赋值
const PI = 3.14159;
PI = 3.14; // TypeError
// const 对象属性可以修改
const obj = { name: 'John' };
obj.name = 'Jane'; // 可以
obj.age = 30; // 可以暂时性死区:
javascript
console.log(x); // undefined
var x = 10;
console.log(y); // ReferenceError(暂时性死区)
let y = 20;2. 解构赋值
问题:如何使用解构赋值?
答案:
数组解构:
javascript
// 基本解构
const [a, b, c] = [1, 2, 3];
console.log(a, b, c); // 1 2 3
// 跳过元素
const [first, , third] = [1, 2, 3];
console.log(first, third); // 1 3
// 剩余元素
const [head, ...tail] = [1, 2, 3, 4];
console.log(head); // 1
console.log(tail); // [2, 3, 4]
// 默认值
const [x = 1, y = 2] = [3];
console.log(x, y); // 3 2
// 交换变量
let m = 1, n = 2;
[m, n] = [n, m];
console.log(m, n); // 2 1对象解构:
javascript
// 基本解构
const { name, age } = { name: 'John', age: 30 };
console.log(name, age); // John 30
// 重命名
const { name: userName, age: userAge } = { name: 'John', age: 30 };
console.log(userName, userAge); // John 30
// 默认值
const { x = 1, y = 2 } = { x: 3 };
console.log(x, y); // 3 2
// 嵌套解构
const user = {
name: 'John',
address: {
city: 'New York',
country: 'USA'
}
};
const { address: { city } } = user;
console.log(city); // New York
// 函数参数解构
function greet({ name, age = 25 }) {
console.log(`Hello, ${name}. You are ${age} years old.`);
}
greet({ name: 'John' }); // Hello, John. You are 25 years old.3. 模板字符串
问题:模板字符串有哪些特性?
答案:
javascript
// 基本使用
const name = 'John';
const greeting = `Hello, ${name}!`;
console.log(greeting); // Hello, John!
// 多行字符串
const multiLine = `
Line 1
Line 2
Line 3
`;
// 表达式
const a = 10, b = 20;
const sum = `Sum: ${a + b}`; // Sum: 30
// 函数调用
const result = `Uppercase: ${name.toUpperCase()}`; // Uppercase: JOHN
// 标签模板
function tag(strings, ...values) {
console.log(strings); // ['Hello ', '!']
console.log(values); // ['John']
return strings[0] + values[0] + strings[1];
}
const tagged = tag`Hello ${name}!`;
console.log(tagged); // Hello John!
// HTML 转义
function html(strings, ...values) {
return strings.reduce((result, str, i) => {
const value = values[i] || '';
return result + str + value.replace(/&/g, '&');
}, '');
}
const userInput = '<script>alert("XSS")</script>';
const safeHtml = html`<div>${userInput}</div>`;4. 箭头函数
问题:箭头函数有什么特点?
答案:
特点:
javascript
// 简洁语法
const add = (a, b) => a + b;
const square = x => x * x;
const greet = () => console.log('Hello');
// 单行返回
const multiply = (a, b) => a * b;
// 多行返回
const calculate = (a, b) => {
const sum = a + b;
const product = a * b;
return { sum, product };
};
// 没有 this 绑定
const obj = {
name: 'John',
sayName: function() {
const arrow = () => {
console.log(this.name); // 'John'(继承外层 this)
};
arrow();
}
};
// 没有 arguments 对象
const test = () => {
console.log(arguments); // ReferenceError
};
// 不能作为构造函数
const Person = (name) => {
this.name = name;
};
const person = new Person('John'); // TypeErrorthis 绑定:
javascript
// 普通函数
const obj = {
name: 'John',
regular: function() {
setTimeout(function() {
console.log(this.name); // undefined
}, 100);
}
};
// 箭头函数
const obj2 = {
name: 'John',
arrow: function() {
setTimeout(() => {
console.log(this.name); // 'John'
}, 100);
}
};5. 扩展运算符和剩余参数
问题:如何使用扩展运算符和剩余参数?
答案:
扩展运算符:
javascript
// 数组扩展
const arr1 = [1, 2, 3];
const arr2 = [4, 5, 6];
const combined = [...arr1, ...arr2]; // [1, 2, 3, 4, 5, 6]
// 数组复制
const copy = [...arr1]; // [1, 2, 3]
// 对象扩展
const obj1 = { a: 1, b: 2 };
const obj2 = { c: 3, d: 4 };
const merged = { ...obj1, ...obj2 }; // { a: 1, b: 2, c: 3, d: 4 }
// 对象复制
const objCopy = { ...obj1 }; // { a: 1, b: 2 }
// 函数参数
function sum(a, b, c) {
return a + b + c;
}
const numbers = [1, 2, 3];
sum(...numbers); // 6
// 数组去重
const arr = [1, 2, 2, 3, 3, 4];
const unique = [...new Set(arr)]; // [1, 2, 3, 4]剩余参数:
javascript
// 收集剩余参数
function sum(...numbers) {
return numbers.reduce((acc, num) => acc + num, 0);
}
sum(1, 2, 3, 4); // 10
// 部分参数 + 剩余参数
function greet(greeting, ...names) {
names.forEach(name => {
console.log(`${greeting}, ${name}!`);
});
}
greet('Hello', 'John', 'Jane', 'Bob');6. 类(Class)
问题:ES6 的 Class 语法如何使用?
答案:
基本语法:
javascript
class Person {
// 构造函数
constructor(name, age) {
this.name = name;
this.age = age;
}
// 实例方法
sayHello() {
console.log(`Hello, I'm ${this.name}`);
}
// 静态方法
static createAnonymous() {
return new Person('Anonymous', 0);
}
}
const person = new Person('John', 30);
person.sayHello(); // Hello, I'm John
const anonymous = Person.createAnonymous();继承:
javascript
class Animal {
constructor(name) {
this.name = name;
}
speak() {
console.log(`${this.name} makes a sound`);
}
}
class Dog extends Animal {
constructor(name, breed) {
super(name); // 调用父类构造函数
this.breed = breed;
}
speak() {
console.log(`${this.name} barks`);
}
fetch() {
console.log(`${this.name} fetches the ball`);
}
}
const dog = new Dog('Buddy', 'Golden Retriever');
dog.speak(); // Buddy barks
dog.fetch(); // Buddy fetches the ballGetter 和 Setter:
javascript
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.area); // 78.5398...
circle.radius = 10;
console.log(circle.area); // 314.159...7. 模块化
问题:ES6 模块如何使用?
答案:
导出:
javascript
// 命名导出
export const PI = 3.14159;
export function add(a, b) {
return a + b;
}
export class Calculator {
add(a, b) {
return a + b;
}
}
// 默认导出
export default function greet(name) {
console.log(`Hello, ${name}!`);
}
// 混合导出
export const greeting = 'Hello';
export default function sayHello() {
console.log(greeting);
}导入:
javascript
// 导入默认导出
import greet from './greet.js';
greet('John');
// 导入命名导出
import { PI, add, Calculator } from './math.js';
console.log(PI);
console.log(add(1, 2));
const calc = new Calculator();
// 导入所有
import * as math from './math.js';
console.log(math.PI);
console.log(math.add(1, 2));
// 重命名导入
import { add as sum } from './math.js';
console.log(sum(1, 2));
// 只导入模块(执行副作用)
import './styles.css';8. Promise
问题:Promise 如何使用?
答案:
基本用法:
javascript
// 创建 Promise
const promise = new Promise((resolve, reject) => {
setTimeout(() => {
const success = true;
if (success) {
resolve('Success!');
} else {
reject('Failed!');
}
}, 1000);
});
// 使用 Promise
promise
.then(result => {
console.log(result); // Success!
})
.catch(error => {
console.error(error); // Failed!
})
.finally(() => {
console.log('Promise completed');
});链式调用:
javascript
fetch('/api/user')
.then(response => response.json())
.then(user => {
console.log(user);
return fetch(`/api/posts/${user.id}`);
})
.then(response => response.json())
.then(posts => {
console.log(posts);
})
.catch(error => {
console.error('Error:', error);
});Promise 静态方法:
javascript
// Promise.all - 所有成功
Promise.all([
fetch('/api/users'),
fetch('/api/posts'),
fetch('/api/comments')
])
.then(responses => {
console.log('All requests completed');
})
.catch(error => {
console.error('One request failed');
});
// Promise.race - 第一个完成
Promise.race([
fetch('/api/fast'),
fetch('/api/slow')
])
.then(response => {
console.log('First request completed');
});
// Promise.allSettled - 所有完成
Promise.allSettled([
Promise.resolve('Success'),
Promise.reject('Error')
])
.then(results => {
results.forEach(result => {
if (result.status === 'fulfilled') {
console.log(result.value);
} else {
console.error(result.reason);
}
});
});
// Promise.any - 第一个成功
Promise.any([
Promise.reject('Error 1'),
Promise.reject('Error 2'),
Promise.resolve('Success')
])
.then(result => {
console.log(result); // Success
});9. async/await
问题:async/await 如何使用?
答案:
基本用法:
javascript
// async 函数
async function fetchData() {
try {
const response = await fetch('/api/data');
const data = await response.json();
return data;
} catch (error) {
console.error('Error:', error);
throw error;
}
}
// 使用
fetchData()
.then(data => console.log(data))
.catch(error => console.error(error));并行执行:
javascript
// 串行执行
async function sequential() {
const user = await fetch('/api/user');
const posts = await fetch('/api/posts');
const comments = await fetch('/api/comments');
return { user, posts, comments };
}
// 并行执行
async function parallel() {
const [user, posts, comments] = await Promise.all([
fetch('/api/user'),
fetch('/api/posts'),
fetch('/api/comments')
]);
return { user, posts, comments };
}错误处理:
javascript
// try-catch
async function withTryCatch() {
try {
const data = await fetchData();
return data;
} catch (error) {
console.error('Error:', error);
return null;
}
}
// .catch()
async function withCatch() {
const data = await fetchData().catch(error => {
console.error('Error:', error);
return null;
});
return data;
}10. 新特性(ES7-ES12)
问题:ES7-ES12 有哪些新特性?
答案:
ES7 (2016):
javascript
// 指数运算符
2 ** 3; // 8
// Array.prototype.includes
[1, 2, 3].includes(2); // trueES8 (2017):
javascript
// async/await
// Object.values()
Object.values({ a: 1, b: 2 }); // [1, 2]
// Object.entries()
Object.entries({ a: 1, b: 2 }); // [['a', 1], ['b', 2]]
// String.prototype.padStart/padEnd
'hello'.padStart(10, 'x'); // 'xxxxxhello'
'hello'.padEnd(10, 'x'); // 'helloxxxxx'
// Object.getOwnPropertyDescriptors
const obj = { a: 1 };
Object.getOwnPropertyDescriptors(obj);ES9 (2018):
javascript
// 异步迭代
async function asyncIterate() {
const asyncIterable = createAsyncIterable();
for await (const item of asyncIterable) {
console.log(item);
}
}
// Promise.prototype.finally
fetch('/api/data')
.then(response => response.json())
.catch(error => console.error(error))
.finally(() => console.log('Cleanup'));
// Object rest/spread
const { a, b, ...rest } = { a: 1, b: 2, c: 3, d: 4 };
console.log(rest); // { c: 3, d: 4 }ES10 (2019):
javascript
// Array.prototype.flat
[1, [2, [3]]].flat(2); // [1, 2, 3]
// Array.prototype.flatMap
[1, 2, 3].flatMap(x => [x, x * 2]); // [1, 2, 2, 4, 3, 6]
// Object.fromEntries
Object.fromEntries([['a', 1], ['b', 2]]); // { a: 1, b: 2 }
// String.prototype.trimStart/trimEnd
' hello '.trimStart(); // 'hello '
' hello '.trimEnd(); // ' hello'ES11 (2020):
javascript
// 可选链
const user = { name: 'John', address: { city: 'New York' } };
const city = user?.address?.city; // 'New York'
// 空值合并
const name = user.name ?? 'Anonymous'; // 'John'
const age = user.age ?? 0; // 0
// BigInt
const bigNumber = 9007199254740991n;
bigNumber + 1n; // 9007199254740992n
// Promise.allSettled
// 动态 import()
const module = await import('./module.js');ES12 (2021):
javascript
// String.prototype.replaceAll
'hello world'.replaceAll('l', 'L'); // 'heLLo worLd'
// Promise.any
// 数字分隔符
const billion = 1_000_000_000;
// 逻辑赋值运算符
a ||= b; // a = a || b
a &&= b; // a = a && b
a ??= b; // a = a ?? b