350个特性看透ES6
介绍
- ES6(也称为Harmony,
es-next
ES2015)是该语言的最新最终定稿规范 - 该ES6规范是在完成2015年6月,(因此ES2015)
- 规范的将来版本将遵循该
ES[YYYY]
模式,例如ES2016 for ES7- 年度发布时间表,不会让您失望的功能会影响下一班火车
- 由于ES6早于该决定,因此我们大多数人仍将其称为ES6。
- 从ES2016(ES7)开始,我们应该开始使用该
ES[YYYY]
模式来引用较新的版本 - 命名方案的首要原因是迫使浏览器供应商迅速实施最新功能
Babel
- 要使ES6今天开始工作,您需要一个JavaScript到JavaScript的 编译器
- 转运者在这里停留
- 它们使您可以将最新版本的代码编译为该语言的旧版本。
- 随着浏览器支持的改善,我们将把ES2016和ES2017转换为ES6及更高版本
- 我们需要更好的源映射功能
- 它们是当今在生产中运行ES6源代码的最可靠方法(尽管浏览器获得了ES5)
- Babel (翻译员)具有杀手级功能:可读的输出
- 用于
babel
将ES6转换为ES5进行静态构建 - 使用
babelify
纳入babel
到你的咕嘟咕嘟,咕噜,或npm run
构建过程 - 使用Node.js
v4.x.x
或更高版本,因为它们具有不错的ES6支持,这要归功于v8
- 使用
babel-node
与任何版本node
,因为它transpiles模块到ES5 - Babel拥有一个蓬勃发展的生态系统,已经支持某些ES2016,并具有插件支持
- 阅读ES6工具简史
分配解构
var {foo} = pony
相当于var foo = pony.foo
var {foo: baz} = pony
相当于var baz = pony.foo
- 您可以提供默认值,
var {foo='bar'} = baz
收益率foo: 'bar'
如果baz.foo
是undefined
- 您可以根据需要提取任意数量的属性(带别名或不带别名)
var {foo, bar: baz} = {foo: 0, bar: 1}
让你foo: 0
和baz: 1
- 您可以更深入。
var {foo: {bar}} = { foo: { bar: 'baz' } }
让你bar: 'baz'
- 您也可以使用别名。
var {foo: {bar: deep}} = { foo: { bar: 'baz' } }
让你deep: 'baz'
- 找不到的属性
undefined
照常产生,例如:var {foo} = {}
- 找不到的深层嵌套属性会产生错误,例如:
var {foo: {bar}} = {}
- 它也适用于数组,
[a, b] = [0, 1]
收益率a: 0
和b: 1
- 您可以跳过数组中的项目
[a, , b] = [0, 1, 2]
,,获取a: 0
和b: 2
- 您可以不使用“ aux”变量进行交换,
[a, b] = [b, a]
- 您还可以在函数参数中使用解构
- 分配默认值,例如
function foo (bar=2) {}
- 这些默认值也可以是对象
function foo (bar={ a: 1, b: 2 }) {}
bar
完全破坏,就像function foo ({ a=1, b=2 }) {}
- 如果未提供任何内容,则默认为空对象,例如
function foo ({ a=1, b=2 } = {}) {}
- 分配默认值,例如
- 深入阅读ES6 JavaScript分解
传播算子和剩余参数
- 其余参数更好
arguments
- 您可以在方法签名中声明它,例如
function foo (...everything) {}
everything
是一个数组,所有参数都传递给foo
- 您可以在之前命名一些参数
...everything
,例如function foo (bar, ...rest) {}
- 命名参数不包括在内
...rest
...rest
必须是列表中的最后一个参数
- 您可以在方法签名中声明它,例如
- 扩展运算符比魔术更好,也用
...
语法 表示- 避免
.apply
在调用方法时,fn(...[1, 2, 3])
等效于fn(1, 2, 3)
- 串联比较容易
[1, 2, ...[3, 4, 5], 6, 7]
- 将类似数组或可迭代对象的类型转换为数组,例如
[...document.querySelectorAll('img')]
- 在解构时也很有用,
[a, , ...rest] = [1, 2, 3, 4, 5]
产量a: 1
和rest: [3, 4, 5]
- 使
new
+.apply
毫不费力,new Date(...[2015, 31, 8])
- 避免
- 深入阅读ES6传播和黄油
箭头函数
- 声明函数的简洁方式
param => returnValue
- 在做类似功能的事情时很有用
[1, 2].map(x => x * 2)
- 有几种口味可供选择,可能会让您习惯一些
p1 => expr
可以使用单个参数p1 => expr
return
对提供的expr
表达式有一个隐式语句- 要隐式返回对象,请将其包装在括号中,
() => ({ foo: 'bar' })
否则会出现错误 - 当您有零个,两个或更多参数时,需要括号,
() => expr
或者(p1, p2) => expr
- 右侧的括号代表一个代码块,可以包含多个语句,
() => {}
- 使用代码块时,没有隐式
return
,您必须提供它-() => { return 'foo' }
- 您不能静态地命名箭头函数,但是现在运行时可以更好地为大多数方法推断名称
- 箭头函数绑定到其词法范围
this
this
与父范围中的上下文相同this
不能使用.call
,.apply
或类似的“反射”型方法进行修改
- 深入阅读ES6箭头功能
模板文字
- 除了
"
和`' 外,还可以使用```(反引号)声明字符串。 - 用反引号括起来的字符串是模板文字
- 模板文字可以是多行
- 模板文字允许插值,例如变量是
ponyfoo.com is ${rating}
哪里rating
- 您可以在插值中使用任何有效的JavaScript表达式,例如
${2 * 3}
或${foo()}
- 您可以使用标记的模板来更改表达式的内插方式
fn
为fn
foo,$ {bar}和$ {baz} 添加前缀fn
被调用一次template, ...expressions
template
是['foo, ', ' and ', '']
和expressions
是[bar, baz]
- 的结果
fn
成为模板文字的值 - 可能的用例包括表达式的输入清理,参数解析等。
- 模板文字几乎严格比单引号或双引号引起来的字符串更好
- 深入阅读ES6模板文字
对象文字
- 代替
{ foo: foo }
,您可以做{ foo }
–称为属性值的简写 - 计算的属性名称
{ [prefix + 'Foo']: 'bar' }
,其中prefix: 'moz'
产生{ mozFoo: 'bar' }
- 您不能将计算出的属性名称和属性值速记组合在一起,
{ [foo] }
无效 - 可以使用其他更简洁的语法声明对象文字中的方法定义,
{ foo () {} }
- 参见
Object
节 - 深入阅读ES6对象文字功能
原型
- 不是“传统”类,而是在原型继承之上的语法糖
- 类似于声明对象的语法,
class Foo {}
- 实例方法-
new Foo().bar
-使用的是短申报对象文本语法,class Foo { bar () {} }
- 静态方法–
Foo.isPonyFoo()
–需要static
关键字前缀,class Foo { static isPonyFoo () {} }
- 构造方法
class Foo { constructor () { /* initialize instance */ } }
- 使用简单语法的原型继承
class PonyFoo extends Foo {}
- 深入阅读ES6类
let和const
let
并且const
是var
声明变量时的替代方法let
是块作用域的,而不是词法范围的function
let
被提升到块的顶部,而var
声明被提升到函数的顶部- “临时死区” – TDZ的简称
- 从
let foo
声明的块的开头开始 let foo
在用户代码中放置该语句的结尾(此处无关紧要)- 尝试访问
foo
TDZ 或在TDZ内进行分配(在let foo
到达该语句之前)会导致错误 - 在声明变量之前对其进行操作时,有助于防止神秘的错误
- 从
const
也受TDZ语义的块作用域,提升和约束const
变量必须使用初始化程序声明,const foo = 'bar'
const
初始化后分配给,失败时会无声地(或在严格模式下大声地 除外)const
变量不会使分配的值不变const foo = { bar: 'baz' }
意味着foo
将始终引用右侧对象const foo = { bar: 'baz' }; foo.bar = 'boo'
不会扔
- 声明相同名称的变量将引发
- 旨在修复在您重新分配变量并丢失其他地方传递的引用的错误
- 在ES6中,功能是块作用域的
- 防止通过吊装泄漏窥探范围内的机密,
{ let _foo = 'secret', bar = () => _foo; }
- 在大多数情况下都不会破坏用户代码,通常情况下无论如何都不会破坏用户代码
- 防止通过吊装泄漏窥探范围内的机密,
- 阅读ES6 Let,Const和“临时死区”(TDZ)的深度
symbol
- ES6中的新原始类型
- 您可以使用创建自己的符号
var symbol = Symbol()
- 您可以添加说明以进行调试,例如
Symbol('ponyfoo')
- 符号是不变的且唯一的。
Symbol()
,Symbol()
,Symbol('foo')
并且Symbol('foo')
都不同 - 符号的类型为
symbol
,因此:typeof Symbol() === 'symbol'
- 您还可以使用以下命令创建全局符号
Symbol.for(key)
- 如果提供的符号
key
已经存在,您将获得该符号 - 否则,还将使用
key
描述作为新符号 Symbol.keyFor(symbol)
是反函数,取asymbol
并返回其key
- 全局符号尽可能具有全局性,即跨领域。单个注册表用于在运行时中查找这些符号
window
语境eval
语境<iframe>
上下文Symbol.for('foo') === iframe.contentWindow.Symbol.for('foo')
- 如果提供的符号
- 还有“知名”符号
- 不在全局注册表中,可通过访问
Symbol[name]
,例如:Symbol.iterator
- 跨领域的意思
Symbol.iterator === iframe.contentWindow.Symbol.iterator
- 通过说明书中使用来定义协议中,如可迭代协议在
Symbol.iterator
- 他们实际上并不知名 -用口语来说
- 不在全局注册表中,可通过访问
- 遍历符号属性很困难,但并非不可能,而且绝对不是私有的
- 所有ES6之前的“反射”方法都将符号隐藏起来
- 可通过以下方式访问符号
Object.getOwnPropertySymbols
- 您不会偶然发现它们,但如果积极寻找,就会找到它们
- 深入阅读ES6符号
迭代器
- 迭代器和可迭代协议定义了如何迭代任何对象,而不仅仅是数组和类似数组的对象
- 一个众所周知的
Symbol
用于将迭代器分配给任何对象 var foo = { [Symbol.iterator]: iterable}
, 要么foo[Symbol.iterator] = iterable
- 的
iterable
是返回的方法iterator
,其具有对象next
方法 - 该
next
方法返回具有两个属性的对象,value
并且done
- 该
value
属性指示要迭代的序列中的当前值 - 该
done
属性指示是否还有其他项目要迭代
- 该
- 具有
[Symbol.iterator]
值的对象是可迭代的,因为它们订阅了可迭代协议 - 在ES6中
Array
,某些内置插件(例如,String
或arguments
)以及NodeList
浏览器默认是可迭代的 - 可迭代对象可以使用进行循环
for..of
,例如for (let el of document.querySelectorAll('a'))
- 可以使用散布运算符来合成可迭代对象,例如
[...document.querySelectorAll('a')]
- 您还可以
Array.from(document.querySelectorAll('a'))
用于将可迭代序列合成为数组 - 迭代器是惰性的,并且产生无限序列的迭代器仍可以导致有效程序
- 要小心,不要试图用合成的无限序列
...
或Array.from
作为会导致无限循环 - 深入了解ES6迭代器
generator
- 生成器函数是一种特殊的迭代器,可以使用以下
function* generator () {}
语法进行声明: - 生成器函数用于
yield
发出元素序列 - 生成器函数还可以
yield*
用于委派给另一个生成器函数–或任何可迭代对象 - 生成器函数返回遵循迭代器和迭代器协议 的生成器对象
- 给定
g = generator()
,g
因为这g[Symbol.iterator]
是一种方法,所以遵守可迭代协议 - 给定
g = generator()
,g
坚持使用迭代器协议,因为它g.next
是一种方法 - 生成器对象的迭代器
g
是生成器本身:g[Symbol.iterator]() === g
- 给定
- 使用提取值
Array.from(g)
,[...g]
,for (let item of g)
,或只调用g.next()
- 在四种不同情况下,生成器函数的执行被挂起,记住最后一个位置
- 甲
yield
表达序列中返回的下一个值 - 一条
return
语句返回序列中的最后一个值 - 一条
throw
语句完全停止了生成器中的执行 - 到达发电机功能信号的末端
{ done: true }
- 甲
- 一旦
g
序列已经结束,g.next()
只是返回{ done: true }
,并没有影响 - 使异步流感到同步很容易
- 采取用户提供的发电机功能
- 发生异步操作时,用户代码被挂起
- 调用
g.next()
,在用户代码中暂停执行
- 深入了解ES6生成器
Promise
- 遵循
Promises/A+
规范,在ES6标准化之前在野外广泛实施(例如bluebird
) - 承诺就像一棵树。使用
p.then(handler)
和添加分支p.catch(handler)
- 与创造新的
p
承诺new Promise((resolve, reject) => { /* resolver */ })
- 该
resolve(value)
回调将履行与所提供的承诺value
- 该
reject(reason)
回调将拒绝p
与reason
错误 - 您可以异步调用这些方法,从而阻止承诺树的更深层分支
- 该
- 每次呼叫
p.then
并p.catch
创建另一个诺言,该诺言在p
结算时被阻止 - 在承诺开始时挂起状态,并定居时,他们要么履行或拒绝
- 承诺只能解决一次,然后解决。已兑现的承诺解除了更深层次的分支
- 您可以根据需要在任意数量的分支上兑现尽可能多的承诺
- 每个分支将执行一个
.then
或多个.catch
处理程序,从不执行 - 一个
.then
回调,可以返回一个值变换先前分支的结果 - 一个
.then
回调可以返回它的另一个承诺阻止 p.catch(fn).catch(fn)
不会做您想要做的-除非您想要做的是在错误处理程序中捕获错误Promise.resolve(value)
创建提供的承诺value
Promise.reject(reason)
创建一个被提供的拒绝的承诺reason
Promise.all(...promises)
创建一个承诺,当所有条件...promises
都满足或其中之一被拒绝时就解决Promise.race(...promises)
创建一个承诺,只要其中一个解决,就...promises
可以解决- 使用Promisees(承诺可视化游乐场)来更好地了解承诺
- 深入阅读ES6承诺
地图
- 替换了使用普通JavaScript对象创建哈希图的常见模式
- 避免了用户提供的密钥的安全性问题
- 允许键为任意值,您甚至可以将DOM元素或函数用作
key
条目的
Map
遵守迭代协议- 创建一个
map
使用new Map()
- 初始化地图与
iterable
像[[key1, value1], [key2, value2]]
在new Map(iterable)
- 使用
map.set(key, value)
添加条目 - 使用
map.get(key)
来获得入门 - 检查
key
使用map.has(key)
- 删除条目
map.delete(key)
map
使用for (let [key, value] of map)
,传播算子Array.from
等进行迭代- 深入阅读ES6地图
WeakMap
- 与相似
Map
,但不完全相同 WeakMap
没有迭代,这样你就不会得到枚举的方法一样.forEach
,.clear
和别人对你的了Map
WeakMap
键必须是引用类型。您不能将符号,数字或字符串之类的值类型用作键WeakMap
key
唯一引用了所引用变量的条目将受到垃圾回收- 最后一点意味着
WeakMap
可以很好地保留对象的元数据,而这些对象仍在使用中 - 您可以避免内存泄漏,而无需进行手动引用计数–
WeakMap
就像IDisposable
在.NET中一样 - 深入阅读ES6 WeakMaps
Set
WeakSet
WeakSet
是Set
和之间的杂种WeakMap
- A
WeakSet
是一个不能迭代且没有枚举方法的集合 WeakSet
值必须是引用类型WeakSet
对于指示引用是否正在积极使用的元数据表可能很有用- 深入阅读ES6弱集
Proxy
- 使用创建代理
new Proxy(target, handler)
,其中target
任何对象handler
都是配置 - a的默认行为
proxy
充当基础target
对象的传递 - 处理程序确定如何在
target
常规对象属性访问语义之上访问基础对象 - 您放弃对的引用,
proxy
并严格控制如何target
与之交互 - 处理程序也称为陷阱,这些术语可互换使用
- 您可以使用以下方式创建可撤销的代理
Proxy.revocable(target, handler)
- 该方法返回具有
proxy
和revoke
属性的对象 - 您可以为了方便而破坏
var {proxy, revoke} = Proxy.revocable(target, handler)
- 您可以将
proxy
所有配置与new Proxy(target, handler)
- 之后
revoke()
被调用时,proxy
将抛出的任何操作,使其在方便的时候你不能相信消费者
- 该方法返回具有
get
–陷阱proxy.prop
和proxy['prop']
set
–陷阱proxy.prop = value
和proxy['prop'] = value
has
–陷阱in
算子deleteProperty
–陷阱delete
算子defineProperty
–陷阱Object.defineProperty
和声明性替代enumerate
–陷阱for..in
循环ownKeys
–陷阱Object.keys
和相关方法apply
–陷阱函数调用construct
–限制new
操作员的使用getPrototypeOf
–捕获内部呼叫[[GetPrototypeOf]]
setPrototypeOf
–陷阱呼叫Object.setPrototypeOf
isExtensible
–陷阱呼叫Object.isExtensible
preventExtensions
–陷阱呼叫Object.preventExtensions
getOwnPropertyDescriptor
–陷阱呼叫Object.getOwnPropertyDescriptor
- 深入阅读ES6代理
- 深入阅读ES6代理陷阱
- 了解更多深入了解ES6代理陷阱
反射
Reflection
是Math
ES6中新的静态内置(认为)Reflection
方法具有合理的内部,例如,Reflect.defineProperty
返回布尔值而不是抛出Reflection
每个代理陷阱处理程序都有一个方法,它们代表每个陷阱的默认行为- 展望未来,新的反射方法
Object.keys
将与Reflection
命名空间相同 - 阅读《ES6深度思考》
Number
0b
对二进制文件使用前缀,0o
对八进制整数文字使用前缀Number.isNaN
而Number.isFinite
像他们的全球同名,但他们不把输入到Number
Number.parseInt
并Number.parseFloat
与他们的全球同名完全相同Number.isInteger
检查输入是否为Number
不带小数部分的值Number.EPSILON
帮助找出两个数字之间可忽略的差异–例如0.1 + 0.2
和0.3
Number.MAX_SAFE_INTEGER
是可以安全且精确地用JavaScript表示的最大整数Number.MIN_SAFE_INTEGER
是可以安全且精确地用JavaScript表示的最小整数Number.isSafeInteger
检查整数是否在这些范围内,可以安全且准确地表示- 阅读ES6
Number
深度改进
Math
Math.sign
–数字的符号功能Math.trunc
–数字的整数部分Math.cbrt
–价值的立方根,或∛‾value
Math.expm1
-e
在value
零下1
,或e<sup>value</sup> - 1
Math.log1p
–value + 1
或的自然对数_ln_(value + 1)
Math.log10
–以value
或10为底的对数_log_<sub>10</sub>(value)
Math.log2
–value
或的以2为底的对数_log_<sub>2</sub>(value)
Math.sinh
–双曲正弦数Math.cosh
–双曲余弦数Math.tanh
–数字的双曲正切Math.asinh
–数字的双曲反正弦Math.acosh
–双曲余弦Math.atanh
–数字的双曲反正切Math.hypot
–平方和的平方根Math.clz32
–数字的32位表示形式中的前导零位Math.imul
– 类似C的 32位乘法Math.fround
–数字的最接近的单精度浮点表示- 深入阅读ES6
Math
添加
Array
Array.from
–Array
从类似数组arguments
或可迭代对象的对象创建实例Array.of
–类似new Array(...items)
,但没有特殊情况Array.prototype.copyWithin
–将一系列数组元素复制到数组中的其他位置Array.prototype.fill
–用提供的值填充现有数组的所有元素Array.prototype.find
–返回满足回调的第一项Array.prototype.findIndex
–返回满足回调的第一项的索引Array.prototype.keys
–返回一个迭代器,该迭代器产生一个序列,该序列包含数组的键Array.prototype.values
–返回一个迭代器,该迭代器产生一个保存数组值的序列Array.prototype.entries
–返回一个迭代器,该迭代器产生一个包含数组的键值对的序列Array.prototype[Symbol.iterator]
–与Array.prototype.values
方法完全相同- 深入阅读ES6
Array
扩展
Object
Object.assign
–对来自的属性进行递归的浅覆盖target, ...objects
Object.is
–像以===
编程方式使用运算符一样,也true
适用于NaN
vsNaN
和+0
vs-0
Object.getOwnPropertySymbols
–返回在对象上找到的所有自己的属性符号Object.setPrototypeOf
–更改原型。相当于target.__proto__
二传手- 另请参见“ 对象文字”部分
- 阅读ES6
Object
深度更改
字符串和Unicode
- 字符串操作
String.prototype.startsWith
–字符串是否以value
String.prototype.endsWith
–字符串是否结尾value
String.prototype.includes
–字符串是否包含value
任何地方String.prototype.repeat
–返回字符串重复amount
次数String.prototype[Symbol.iterator]
–使您可以遍历一系列Unicode代码点(非字符)
- 统一码
String.prototype.codePointAt
–字符串中给定位置的代码点的以10为基的数字表示String.fromCodePoint
–给定...codepoints
,返回由其unicode表示形式组成的字符串String.prototype.normalize
–返回字符串的unicode表示形式的规范化版本
- 深入阅读ES6字符串和Unicode添加
模块系统
- ES6模块系统中默认情况下严格模式已打开
- ES6模块是
export
API的文件 export default value
导出默认绑定export var foo = 'bar'
导出命名绑定- 命名导出是可以在导出它们的模块中随时更改的绑定
export { foo, bar }
出口已命名出口的清单export { foo as ponyfoo }
别名出口为引用ponyfoo
,而不是export { foo as default }
将命名的出口标记为默认出口- 作为最佳实践,
export default api
在所有模块的末尾,其中api
是一个对象,避免混乱, - 模块加载是特定于实现的,允许与CommonJS互操作
import 'foo'
将foo
模块加载到当前模块中import foo from 'ponyfoo'
将默认导出分配给ponyfoo
本地foo
变量import {foo, bar} from 'baz'
命名出口进口foo
和bar
从baz
模块import {foo as bar} from 'baz'
导入名为exportfoo
但别名为bar
变量的导入import {default} from 'foo'
也导入默认导出import {default as bar} from 'foo'
导入默认导出别名为bar
import foo, {bar, baz} from 'foo'
将默认值foo
与命名导出混合在一起,bar
并baz
在一个声明中import * as foo from 'foo'
导入名称空间对象- 包含以下所有已命名的出口
foo[name]
foo.default
如果在模块中声明了默认导出,则包含中的默认导出
- 包含以下所有已命名的出口
- 深入阅读ES6模块补充
是时候进行子弹头排毒了。再说一遍,我确实警告过您阅读文章系列。别忘了订阅,甚至可以使Pony Foo活着。另外,您是否刚刚尝试了Konami代码?