ES6+有哪些新特性
ES6新增特性
- let 和 const 声明
- 解构(数组、对象解构)-快速提取数组/对象中的元素
- 模板字符串-可以换行、插值、使用标签函数进行字符串操作
- 字符串扩展方法(includes, startsWith, endsWith...)
- 参数默认值和剩余参数
- 扩展运算符
- 箭头函数
- 类和继承
- 对象新增了些方法 (Object.is, Object.assign...)
- Promise
- 模块化 可以使用 import 和 export 关键字来导入和导出模块。
- 新的数据结构 包括 Map、Set、WeakMap 和 WeakSet。
- Proxy 非必需
- Reflect 对象的操作更加统一、灵活和标准化。 非必需
- Symbol
- Iterator 迭代器 和 for...of 循环
- Generator 生成器
FAQ?
es5 中的类和es6中的class有什么区别?
- class类必须new调用,不可以直接执行
- class类不存在变量提升
- class类无法遍历它实例原型链上的属性和方法
- es6为new命令引入了一个new.target属性,它会返回new命令作用于的那个构造函数。如果不是通过new调用或Reflect.construct()调用的,new.target会返回undefined
- class类有static静态方法
你是怎么理解ES6中 Decorator 的?使用场景有哪些?
Decorator(装饰器)是一种与类(class)相关的语法,用来修改和注解类及其成员。它本质上是一个函数,在类声明时被调用,接收被装饰的目标(类、方法、属性等)并返回新的描述或直接修改原目标。装饰器目前仍是提案(TC39 Stage 3),常通过 Babel 编译使用。
基本语法:
// 类装饰器
function loggable(target) {
target.prototype.log = function () {
console.log(this.constructor.name);
};
}
@loggable
class Foo {}
new Foo().log(); // Foo
// 方法装饰器:(target, key, descriptor)
function readonly(target, key, descriptor) {
descriptor.writable = false;
return descriptor;
}
class Person {
@readonly
getName() {
return this.name;
}
}
使用场景:
- 日志、埋点:在方法执行前后统一打印日志或上报数据。
- 权限控制:根据角色决定方法是否可调用。
- 数据校验:校验方法参数或属性赋值。
- 防抖/节流:将普通方法包装成 debounced 方法。
- 类的混入(mixin):动态给类扩展能力。
- 框架中的广泛应用:Angular(组件、依赖注入)、TypeScript 类注解、NestJS(控制器、中间件)等。
装饰器的好处是把与核心业务无关的横切逻辑(日志、权限、校验等)从业务代码中抽离出来,提升可复用性和可维护性。
你是怎么理解ES6中Proxy的?使用场景有哪些?
Proxy 是一种用于创建代理对象的机制,它允许你在目标对象之前设置一个拦截器(handler),从而可以对目标对象的访问进行 控制、修改和扩展。
Proxy 的基本语法如下:
let proxy = new Proxy(target, handler);
target:要代理的目标对象。handler:一个对象,定义了拦截器(handler)函数,可以定制目标对象的行为。
handler解析
关于handler拦截属性,有如下:
- get(target,propKey,receiver):拦截对象属性的读取
- set(target,propKey,value,receiver):拦截对象属性的设置
- has(target,propKey):拦截
propKey in proxy的操作,返回一个布尔值 - deleteProperty(target,propKey):拦截
delete proxy[propKey]的操作,返回一个布尔值 - ownKeys(target):拦截
Object.keys(proxy)、for...in等循环,返回一个数组 - getOwnPropertyDescriptor(target, propKey):拦截
Object.getOwnPropertyDescriptor(proxy, propKey),返回属性的描述对象 - defineProperty(target, propKey, propDesc):拦截
Object.defineProperty(proxy, propKey, propDesc),返回一个布尔值 - preventExtensions(target):拦截
Object.preventExtensions(proxy),返回一个布尔值 - getPrototypeOf(target):拦截
Object.getPrototypeOf(proxy),返回一个对象 - isExtensible(target):拦截
Object.isExtensible(proxy),返回一个布尔值 - setPrototypeOf(target, proto):拦截
Object.setPrototypeOf(proxy, proto),返回一个布尔值 - apply(target, object, args):拦截 Proxy 实例作为函数调用的操作
- construct(target, args):拦截 Proxy 实例作为构造函数调用的操作
使用场景包括但不限于:
Proxy其功能非常类似于设计模式中的代理模式,常用功能如下:
- 拦截和监视外部对对象的访问
- 降低函数或类的复杂度
- 在复杂操作前对操作进行校验或对所需资源进行管理
使用 Proxy 保障数据类型的准确性
let numericDataStore = { count: 0, amount: 1234, total: 14 };
numericDataStore = new Proxy(numericDataStore, {
set(target, key, value, proxy) {
if (typeof value !== 'number') {
throw Error("属性只能是number类型");
}
return Reflect.set(target, key, value, proxy);
}
});
numericDataStore.count = "foo"
// Error: 属性只能是number类型
numericDataStore.count = 333
// 赋值成功
声明了一个私有的 apiKey,便于 api 这个对象内部的方法调用,但不希望从外部也能够访问 api._apiKey
let api = {
_apiKey: '123abc456def',
getUsers: function(){ },
getUser: function(userId){ },
setUser: function(userId, config){ }
};
const RESTRICTED = ['_apiKey'];
api = new Proxy(api, {
get(target, key, proxy) {
if(RESTRICTED.indexOf(key) > -1) {
throw Error(`${key} 不可访问.`);
} return Reflect.get(target, key, proxy);
},
set(target, key, value, proxy) {
if(RESTRICTED.indexOf(key) > -1) {
throw Error(`${key} 不可修改`);
} return Reflect.get(target, key, value, proxy);
}
});
console.log(api._apiKey)
api._apiKey = '987654321'
// 上述都抛出错误
还能通过使用Proxy实现观察者模式
观察者模式(Observer mode)指的是函数自动观察数据对象,一旦对象有变化,函数就会自动执行
observable函数返回一个原始对象的 Proxy 代理,拦截赋值操作,触发充当观察者的各个函数
const queuedObservers = new Set();
const observe = fn => queuedObservers.add(fn);
const observable = obj => new Proxy(obj, {set});
function set(target, key, value, receiver) {
const result = Reflect.set(target, key, value, receiver);
queuedObservers.forEach(observer => observer());
return result;
}
其他、属性访问控制、属性值的验证、函数调用拦截、属性枚举控制、日志记录等
怎么理解ES6中 Generator的?使用场景有哪些?
Generator 是 ES6 提供的一种可以暂停执行、再恢复执行的函数。写法上在 function 关键字后加 *,函数内部通过 yield 表达式定义暂停点。调用 Generator 函数不会立即执行,而是返回一个迭代器(Iterator)对象,通过调用它的 next() 方法依次执行到下一个 yield,返回 { value, done }。
function* gen() {
const a = yield 1;
console.log("a =", a);
const b = yield 2;
console.log("b =", b);
return 3;
}
const it = gen();
it.next(); // { value: 1, done: false }
it.next("AA"); // 打印 a = AA,返回 { value: 2, done: false }
it.next("BB"); // 打印 b = BB,返回 { value: 3, done: true }
Generator 的关键特性:
- 函数体可以分段执行,通过
yield暂停并通过next(value)向内传值。 - 自动实现
Symbol.iterator,因此可被for...of、扩展运算符、解构等消费。 - 可以用
yield*委托给另一个可迭代对象,组合多个生成器。 - 与
Promise配合可以实现异步流程控制(早期co库即基于此)。
使用场景:
- 自定义迭代器:将任意数据结构按规则遍历输出。
- 状态机:利用暂停和恢复表达复杂的状态流转。
- 惰性计算:按需生成无限序列,如斐波那契数列。
- 异步流程控制:
async/await本质就是 Generator + Promise 的语法糖,Babel 编译时也依赖 Generator 的运行时。 - React 中的
redux-saga通过 Generator 组织副作用,让异步代码可测试、易于取消。
ES6中新增的Set、Map两种数据结构怎么理解?
Set是一种叫做集合的数据结构,Map是一种叫做字典的数据结构