ECMAScript新特性 & ES6
2015年开始ES保持每年一个版本的迭代
1、作用域:某个成员能够起作用的范围(目前有三种作用域:全局作用域、函数作用域、块级作用域)
2、const:只读的常量,声明的时候必须设置初始值,后续不可以修改
最佳实践:不用var、主用const、配合let
3、数组的解构
...这种用法只能在解构的最后一个位置上使用
成员个数小于解构个数,会按照从前到后的顺序去提取,多出来的成员不会被提取
解构个数大于数组长度,会打印出undefined
给解构成员加默认值:const { foo, bar, baz = 'baz default value' } = arr 如果未提取到数据会使用默认值
1 let arr = [1, 2, 3]; 2 const { foo, bar, baz } = arr 3 console.log( foo, bar, baz ) // 1 2 3 4 let arr1 = [100, 200, 300] 5 const { foo1, ...rest } = arr1 6 console.log( rest ) // [200, 300]
4、对象的解构
1 const obj = { name: "obz", age: 18 } 2 const { name } = obj 4 const name = 'tom' 5 const { name: objName = 'jake' } = obj
/*
如果名字冲突可以给解构的重新命名 对象中解构的某个名字:重新命名后的该值的名字
如果需要给默认值可以接着在后面用=“默认值”: name: objName = 'jake'
*/
6 console.log( objName )
5、模版字符串
支持换行 可以写多行、差值表达式、
const name = 'tom' const msg = `hey, ${ name } -- ${ 1+2 } --- ${Math.random()}` console.log(msg)
6、带标签的模版字符串
支持换行 可以写多行、差值表达式、
1 const name = 'tom' 2 const gender = true 3 4 function myTagFunc (strings, name, gender ) { 5 console.log( strings, name, gender ) 6 // ['hey,' , 'is a ', '.'] tom true 7 const sex = gender ? 'man' : 'woman' 8 return strings[0] + name + strings[1] + sex + strings[2] 9 } 10 11 const result = myTagFunc(`hey, ${name } is a ${gender}.`) 12 console.log(result) 13
7、字符串的扩展方法
1 const msg = 'Error: foo is not defined.' 2 3 // startsWith 以xxx开始 4 console.log( msg.startsWith('Error') ) 5 6 // endsWith 以xxx结束 7 console.log( msg.endsWith('.') ) 8 9 // includes 是否包含xxx 10 console.log( msg.includes('foo') )
8、参数默认值
没有传递实际参数时,使用的值
1 // 原来的 2 function foo (enable) { 3 enable = enable || true 4 // 如果enable传递false时无法实现 须改为 5 enable = enable == undefiled ? true : enable 6 console.log(enable) 7 } 8 /* 9 新写法: 如果为传入或者为undefiled时用默认值true 10 如果有多个参数时,带默认值的一定要在最后 11 */ 12 function foo (a, enable = true) { 13 console.log(enable) 14 }
9、参数默认值
只能在行参的最后一位,只能出现一次
1 function foo(...args){ 2 console.log(args) // [1, 2, 3, 4] 3 } 4 foo(1, 2, 3, 4) 5 6 // 展开数组 7 const arr = [ 'foo', 'bar', 'baz' ] 8 console.log(...arr) // foo bar baz
10、箭头函数
箭头左侧是传入的值,如果只有一个值可以省略()
箭头右侧是函数对应的方法,如果只有一个返回值可以省略return 和 { }
箭头函数不会改变this指向
在普通函数中,this始终会指向调用这个函数的对象
箭头函数当中没有this的机制,所以不会改变this的指向,也就是说在箭头函数的外面this是什么在里面拿到的this就是什么,任何情况下都不会发生改变
1 function inc (number) { 2 return number + 1 3 } 4 const inc = n => n+1 5 6 console.log(inc(100)) 7 8 const person = { 9 name: 'tom', 10 sayHi: function() { 11 console.log(`hi, my name is ${ this.name }`) // hi, my name is tom 12 } 13 sayHii: () => { 14 console.log(`hi, my name is ${ this.name }`) // hi, my name is undefiled 15 } 16 sayHiAsync: function () { 17 //const _this = this 18 //setTimeout(function(){ 19 //console.log(_this.name) // tom 20 //}, 1000) 21 // 优化为 22 setTimeout(()=>{ 23 console.log(_this.name) // tom 24 }, 1000) 25 } 26 27 }
11、对象字面量的增强
为对象增加动态属性名,现在可以直接用[]使用动态的值
计算属性名: 表达式执行的结果作为属性名
1 const bar = '123' 2 3 const obj = { 4 foo: 123, 5 bar: bar // bar: bar => bar 等价 6 bar, 7 method: function () {}, // 省略 : function 8 method () {}, 9 [Math.random()]: 123, 10 [1+1]: 345 11 }
12、对象扩展方法
Object.assign:讲多个源对象中的属性复制到一个目标对象中
从源对象中取,放到目标对象中
用后面对象中的属性,覆盖第一个对象,返回值是第一个对象
1 const source1 = { 2 a: 123, 3 b: 123 4 } 5 const source2 = { 6 b: 789, 7 d: 789 8 } 9 const target = { 10 a: 456, 11 c: 456 12 } 13 const result = Object.assign(target, source1, source2) 14 console.log(target) // {a:123, c: 456, b: 789, d : 789 } 15 console.log(result === target) // true
Object.is 判断两个值是否相等
0 == false 两等比较前会进行数据转化
0 === false 三等是严格去对比两者是否相等,0和false类型不同,所以不相等
但是三等运算符无法比较+0 === -0 // true NaN === NaN // false
Object.is(+0, -0)
Object.is(NaN, NaN)
13、Proxy
14、Proxy对比DefineProperty
15、Reflect
16、Promise
17、Set数据结构
1 const s = new Set() 2 s.add(1).add(2).add(3).add(2) 3 console.log(s) // Set {1, 2, 3} 4 5 s.forEach(i => console.log(i)) // 1 2 3 6 7 for (let i of s) { console.log(i) } // 1 2 3 8 9 console.log(s.size) // 3 10 11 console.log(s.has(100)) // false 12 13 console.log(s.delete(2)) // true 14 console.log(s) // Set {1, 3} 15 16 s.clear() 17 console.log(s) // Set {} 18 19 // 为数组去重 20 const arr = [1,2,3,2,3,4,5]; 21 const result = new Set(arr) 22 console.log(result) // Set {1, 2, 3, 4, 5} 23 24 // 如果想得到一个新的数组的话 25 const result1 = Array.from(new Set(arr)) 26 const result2 = [...new Set(arr)] 27 console.log(result1, result2) // [1, 2, 3, 4, 5]
18、Map数据结构
可以用任意类型的值作为键
1 const obj = {} 2 obj[true] = 'value' 3 obj[123] = 'value' 4 obj[{a: 1}] = 'value' 5 console.log(Object.keys(obj)) // ["123", "true", "[object Object]"] 6 7 /* 8 对象添加的键不是字符串,那内部就是将toString的结果当成这个键 9 */ 10 11 const m = new Map() 12 const tom = {name: 'tom'} 13 m.set(tom, 90) 14 console.log(m) // Map { {name: tom => 90} } 15 console.log(m.get(tom)) // 90 16 m.has() 17 m.delete() 18 m.clear() 19 20 m.forEach((value, key) => { 21 console.log(value, key) 22 // 90 {name: 'tom'} 23 })
19、Symbol
一种全新的原始数据类型
目前最主要的作用就是为对象添加独一无二的属性名
每次通过Symbol创建的都是唯一的值
1 // shared.js ===== 2 const cache = {} 3 4 // a.js ===== 5 cache['foo'] = Math.random() 6 7 // b.js ==== 8 cache['foo'] = '123' 9 10 /* 11 多页面会造成冲突,之前会约定命名格式,但是如果不遵守约定也会出现重复覆盖的情况,所以可以通过Symbol来解决 12 */ 13 const s = Symbol() 14 console.log(s) // Symbol() 15 console.log( typeof s ) // symbol 16 console.log( Symbol() === Symbol() ) // false 17 console.log(Symbol('foo')) // Symbol(foo) 18 19 const obj = {} 20 obj[Symbol()] = '123' 21 obj[Symbol()] = '456' 22 console.log(obj) 23 // { [Symbol()]: "123", [Symbol()]: "456"} 24 25 const obj1 = { 26 [Symbol()]: '098' 27 } 28 29 30 // a.js ==== 31 const name = Symbol() 32 const person = { 33 [name]: 'zxs', 34 say () { console.log(this[name]) } 35 } 36 37 // b.js ==== 38 person[Symbol()] // undefined 访问不到的 39 person.say() // zxs
const s1 = Symbol.for('foo')
const s2 = Symbol.for('foo')
console.log(s1 === s2) // true
20、for...of循环
作为遍历所有数据结构的统一方式
可以循环可迭代的数据
ES中能够表示有结构的数据类型越来越多,为了给各种各样的数据结构提供统一的遍历方式,ES2015提供了Iterable接口
实现Iterable接口就是for...of循环的前提,只要数据结构实现了Iterable接口,就可以用for...of循环
原型对象中有Symbol(Symbol.iterator)的方法的才可以
1 const arr = [100, 200, 300] 2 3 for(const item of arr){ 4 console.log( item ) // 100 200 300 5 if( item > 100 ){ break } 6 // 可以在for of中可以直接使用关键字break终止遍历 7 } 8 9 const s = new Set(['foo', 'baz']); 10 for ( const item of s ){ 11 console.log(item) // foo baz 12 } 13 14 const m = new Map(); 15 m.set('foo', '123') 16 m.set('bar', '345') 17 for( const item of m){ 18 console.log(item) 19 // ['foo', '123'] ['bar', '345'] 把键和值放到数组中 20 } 21 for( const[key, value] of m){ 22 console.log(key, value) 23 // foo 123 bar 345 24 }
21、ES2016 & ES2017
1 1、Array.prototype.includes => 判断数组中是否存在某一项 2 const arr = ['foo', 1, NaN, false] 3 arr.includes(NaN) // true 4 5 2、指数运算符 6 console.log( Math.pow(2, 10) ) 7 console.log(2 ** 10) 8 9 3、 Object.value: 打印对象中的值,放到一个数组中 10 let obj1 = { foo: 'value1', bar: 'values' } 11 Object.values(obj1); 12 ["value1", "values"] 13 14 4、 Object.entries: 把对象转换成数据,key value为一维数组 15 [ ["foo", "value1"], ["bar", "values"] ] 16 17 for ( const [key, value] of Object.entries(obj1) ){ 18 console.log(key, value) 19 } 20 21 5、 String.prototype.padStart / String.prototype.padEnd : 对齐数据长度 22 用给定字符串填充目标字符串的开始或结尾位置,直到字符串达到指定长度为止 23 const books = { 24 html: 5, 25 css: 16, 26 javascript: 128 27 } 28 29 for ( const [name, count] of Object.entries(books) ){ 30 console.log(`${ name.padEnd(16, '-') } | ${ count.toString().padStart(3, '0') }`) 31 32 // html------------ | 005 css------------- | 016 javascript------ | 128 33 } 34 35 6、 在函数参数中添加结束尾逗号 36 优点:格式一致,重新排列比较方便;新建时只增加新增加的,少改动代码行数