ECMAScript 新特性
ES2015
-
let 和 作用域
- 块级作用域
- 没有变量提升
-
const 常量
-
数组的解构
// 数组解构
const arr = ['1','2','3']
const [a,,c,d = '4'] = arr
const [A,...result] = arr
console.log(a) // ‘1’
console.log(c) // ‘3’
console.log(d) // ‘4’
console.log(A) // ‘A’
console.log(result) // ['2', '3']
- 对象的解构
// 对象解构
const obj = {name:'x', age:18, gander: 'm'}
const {name:firstName , age, gander = 'f', weight = '80'} = obj
console.log(firstName) // x
console.log(age) // 18
console.log(gander) // 'm'
console.log(weight) // '80'
-
模板字符串
-
字符串的扩展方法
- includes()
- startsWith()
- endsWith()
-
参数默认值
// 多个参数, 带默认值的形参要放在最后
function foo1 (enable == true) {
console.log('foo invoked - enable: ');
console.log(enable)
}
foo1(false);
foo1();
foo1(true)
- 剩余参数
function test(...args){
console.log(args)
}
test(1,2,3) // [1,2,3]
- 展开数组
const arr = [1,2,3,4];
console.log(...arr);
-
箭头函数
箭头函数不会改变this指向function foo3(i) { return i + 1; } const inc = n => n + 1; console.log(foo3(100)); // 101 console.log(inc(100)); // 101 const array = [1,3,2,4,5,6,9,7]; array.filter(i => i % 2); // 获取偶数 // 箭头函数不会改变this指向 // 1.普通函数的this:指向它的调用者,如果没有调用者则默认指向window. // 2.箭头函数的this: 指向箭头函数定义时所处的对象,而不是箭头函数使用时所在的对象,默认使用父级的this. const name2 = 'lee'; const person = { name2: 'tom', sayHi1: function(){ console.log('my name is ', this.name2); }, sayHi2: () => { console.log('my name is ', this.name2); }, sayHiAsync: function() { // 1. // setTimeout(function(){ // console.log(this.name); // }, 1000); // undefined 因为异步调用, 无法访问person的那么属性 // 2. // const _this = this; // setTimeout(function(){ // console.log(_this.name2); // },1000) // tome 定义一个_this指向this, 利用闭包的特性, 调用到person // 3. setTimeout(() => { console.log(this.name2); }, 1000); // 箭头函数 this 指向 sayHiAsync 被定义的地方, 即person } } person.sayHi1(); person.sayHi2(); person.sayHiAsync(); -
对象字面量增强
-
Object.assign()
const source1 = {
a: 123,
b: 234,
}
const source2 = {
b: 789,
d: 12345,
}
const target = {
b: 456,
c: 345,
}
const afterTarget = Object.assign(target, source1);
console.log(target);
console.log(afterTarget === target);
// 多个源对象
const afterTarget2 = Object.assign(target,source1, source2);
console.log(target);
- Object.is() 判断相等
console.log(
// 0 == false // true
// 0 === false // false
// +0 === -0 // true
// NaN === NaN // false
// Object.is(+0, -0) // false
Object.is(NaN, NaN) // true
)
-
Proxy vs Object.defineProperty
- 监听对象属性的删除
- 对数组对象的监视(重写数组的操作方法)
- 非侵入式
const person2 = {
name: 'zoe',
age: 20
}
const person2Proxy = new Proxy(person2, {
// get(target, property) {
// console.log(target, property)
// return 100;
// },
get(target, property){
return property in target?target[property] : 'default'
},
set(target, property, value) {
if (property == 'age') {
if (!Number.isInteger(value)) {
throw new TypeError(`${value} is not an int`);
}
}
target[property] = value;
},
deleteProperty(target, property) {
console.log('delete', property);
delete target[property];
}
});
console.log(person2Proxy.name);
console.log(person2Proxy.xxx);
person2Proxy.age = 100;
console.log(person2Proxy.age);
// person2Proxy.age = '101';
// console.log(person2Proxy.age);
delete person2Proxy.age;
console.log(person2);
const list = [];
const listProxy = new Proxy(list, {
set(target, property, value) {
console.log('set', property, value);
target[property] = value;
return true; // 标识设置成功
}
})
listProxy.push(100);
// proxy 相对 object.defineProperty
// object.defineProperty 只能监听对象属性的读写
// proxy 能监视更多对象操作, 例如delete 和 对方法的调用
// proxy 更好的实现了对数组对象的监视
// defineProperty 通过重写数组方法来实现对数组的监视
// proxy 以非侵入的方式监管了对象的读写
- Reflect 静态类(不能new, 与Math相似)
Reflect 属于一个静态类,只能执行静态类的静态方法
// Reflect 内部分装了一系列对对象的底层操作
// Reflect 成员方法就是 Proxy 处理对象的默认实现
// 提供了一套统一的用于操作对象的API
const testObj2 = {
foo: '123',
baz: '234',
}
const proxy2 = new Proxy(testObj2, {
get(target, property) {
// 先实现属性监视逻辑,
// 再实现默认实现方法
// Reflect 类似于 oc 中的 super
console.log('watch, logic');
return Reflect.get(target, property);
}
})
console.log(proxy2.foo);
// Reflect 统一 api
// 原先 多种方法类型
// console.log('foo' in testObj2);
// console.log(delete testObj2['baz'])
// console.log(Object.keys(testObj2));
// 统一方式
console.log(Reflect.has(testObj2, 'foo'));
console.log(Reflect.deleteProperty(testObj2,'baz'));
console.log(Reflect.ownKeys(testObj2));
-
Promise
-
class
- extends
-
Set(数据结构) 唯一 内部成员不允许重复
-
Map(数据结构) 任意数据类型作为键
- .set() 设置值
const m = new Map(); const tom = {name:'tom'}; m.set(tom, 90); m.set('a','1') console.log(m); //Map { { name: 'tom' } => 90, 'a' => '1' }- .get() 取值
- .has() 判断某个键是否存在
- .delete() 删除某个键
- .clear() 清空所有键值
-
Symbol(全新的原始数据类型)
- 为对象添加独一无二的属性名
- 无法通过 for in 或者 Object.keys 拿到Symbol类型的属性名
- JSON.stringfly(obj)也会忽略掉Symbol属性
- 适合作为对象的私有属性
- 可通过 Object.getOwnPropretySymbol(obj) 获取到Symbol类型属性名
const s = Symbol(); console.log(typeof s) // symbol console.log( Symbol() === Symbol() // false // Symbol('foo') === Symbol('foo') // false ) const s1 = Symbol.for('foo'); const s2 = Symbol.for('foo'); console.log(s1, s2); // Symbol(foo) Symbol(foo) console.log(s1 === s2); // true -
BigInt(全新的原始数据类型)
-
for 适合遍历普通数组
-
for ... in 适合遍历键值对
-
for ... of 遍历所有数据结构的统一方式
- 实现Iterable接口是 for...of 的前提
// iterable // 可迭代接口|协议|标准
// 是 for...of 的前提
// 对象内部挂载 iterator 方法
// 返回一个带有next()方法的对象
// 调用next()方法就可以实现对内部所有数据的遍历
const set= new Set(['foo', 'bar', 'baz']);
const iterator = set[Symbol.iterator]();
console.log(iterator.next()); // {value: 'foo', done: false}
console.log(iterator.next()); // {value: 'bar', done: false}
console.log(iterator.next()); // {value: 'baz', done: false}
console.log(iterator.next()); // {value: undefined, done: true}
// iterable // 迭代器接口实现
const obj = {
store: ['foo', 'bar', 'baz'], // 一个数组用于保存要迭代的数据
[Symbol.iterator]: function(){
let index = 0;
const self = this;
return {
next: function() {
const result = {
value: self.store[index],
done: index >= self.store.length ,
} // 实现迭代结果接口, iterationResult, 约定 有一个value属性, 标识当前被迭代到的数据, 任意类型. 一个 done 属性 , 标识是否迭代完成
index ++;
return result;
}
} // 实现迭代器接口, iterator , 约定内部必须实现一个用于迭代的 next() 方法
},
} // 自定义对象, 实现可迭代接口 iterable , 约定内部必须有一个可以返回迭代器的 iterator 方法
for (const item of obj) {
console.log(item);
}
// 迭代器 模式 iterator (用来干什么)
// 场景 任务清单
const todos = {
life: ['吃饭', '睡觉', '打豆豆'],
learn: ['语文','数学','英语'],
work: ['项目A', '项目B'],
each: function (callback) {
const all = [].concat(this.life, this.learn, this.work)
for (const item of all) {
callback(item);
}
}
// 提供一个统一遍历结构, 处理方法可以不用管todos内部的数据结构是什么, 除了life, learn, work 还会有什么别的任务列表
[Symbol.iterator]: function() {
const all = [...this.life, ...this.learn, ...this.work];
let index = 0;
return {
next: function() {
return {
value: all[index],
done: index++ => all.length
}
}
}
}
}
todo.each(function (item) {
console.log(item);
})
for(const item of todos) {
console.log(item);
}
- generator
- ES Module 语言层面的模块化标准
ES2016
- Arrary.prototype.includes 是否存在某一指定元素
- 指数运算符
console.log(2 ** 10) // 1024
ES2017
- Object.values 返回对象所有值组成的一个数组
- Object.entries 以数组形式返回所有键
- Object.getOwnPropertyDescriptors 获取对象属性的详细描述信息
- String.prototype.padStart
- String.proto.padEnd
// 字符串填充方法
// String.prototype.padStart / String.prototype.padEnd
// 可以为数字前面添加0, 也可以用以对齐输出的字符串长度
const obj = {
a: 12,
css: 3421,
javaScript: 129213,
}
for (const [name, count] of Object.entries(obj)) {
console.log(`${name.padEnd(16, '-')}` | `${count.toString.padStart(3, '0')}`);
}
- 在函数中添加尾逗号
- async/await