一、表达式可能有副作用。
function foo(){
a = a + 1
}
let a = 1
foo() // undefined
a // 2
这个函数调用表达式的副作用是a的值被改变。
二、if加if可以有两种写法。
function vowels(str){
let matches
if(str){
matches = str.match(/[aeiou]/g)
if(matches){
return matches
}
}
}
vowels("Hello world")
下面的代码简洁,体现两个条件的关联性。
function vowels(str){
let matches
if(str && (matches = str.match(/[aeiou]/g))){
return matches
}
}
vowels("Hello World")
三、内层循环跳转到外层循环。
foo: for(let i=0;i<4;i++){
for(let j=0;j<4;j++){
if((i*j) >= 3){
console.log("stopping!", i, j)
break foo
}
console.log(i, j)
}
}
// 0 0
// 0 1
// 0 2
// 0 3
// 1 0
// 1 1
// 1 2
// stopping! 1 3
break foo的意思是跳出标签foo所在的循环,继续执行后面的代码。
四、对象的解构赋值。
function getData(){
console.log('here')
return {
a: 42,
b: "foo"
}
}
let {a,b} = getData()
console.log(a,b)
// 42 'foo'
实际上{a, b}就是{a: a, b: b}的简化版本,只不过明显{a, b}更简洁。
五、暂时性死区。
{
typeof a // undefined
typeof b // Uncaught ReferenceError
let b
}
暂时性死区(TDZ)使得以前对未声明变量使用typeof不报错的时代结束了。
六、try ...finally。
function foo(){
try{
return 40
}
finally {
console.log('Hello')
}
console.log('never runs')
console.log('never runs')
console.log('never runs')
}
console.log(foo())
// Hello
// 40
finally中的代码会在try之后执行,如果有catch的话会在catch之后执行,我们可以把finally中的代码看做回调函数,无论出现什么情况都会被调用。上述代码是首先try先执行,将foo()函数的返回值设为40,之后在执行finally。最后执行console.log()显示返回值。
七、Number.isFinite()和Number.isNaN()方法。
Number.isFinite(10) // true
Number.isFinite(NaN) // false
Number.isFinite(0.005) // true
Number.isFinite(Infinity) // false
Number.isFinite("xinhai") // false
Number.isFinite(false) // false
Number.isFinite(true) // true
Number.isNaN(NaN) // true
Number.isNaN('NaN') // false
Number.isNaN('16') // false
Number.isNaN(false) // false
Number.isNaN(true) // false
Number.isNaN(5/NaN) // true
Number.isNaN('false'/0) // true
Number.isNaN('false'/'true') // true
Number.isNaN(false/true) // false
以前的全局方法isFInite和isNaN会先调用Number()将非数值转为数值。上述两个方法只对数值有效,对于非数值全部返回false,Number.isNaN只有NaN才会返回true,其他一律返回false。这两个方法明显优于以前的isFInite和isNaN。感受到ES6在更推荐让我们减少一些全局函数。
八、数学运算误差检查。
function withinErrorMargin(left, right){
return Math.abs(left-right) < Number.EPSILON
}
withinErrorMargin(0.56,0.3+0.260000000000000000000000000000001) // true
withinErrorMargin(0.56,0.300000000000001+0.26) // false
withinErrorMargin(0.56,0.3000000000000001+0.26) // true
其实就是让这个误差小于Number.EPSILON就是认为是相等的。
九、函数参数指定默认值。
function log(x,y) {
y = y || 'World'
console.log(x,y)
}
log('Hello','') // Hello World
参数y指定了赋值,但是其对应的布尔值为false,则该赋值不起作用,依旧会采用默认赋值,这时我们可以加上判断条件。
function log(x,y) {
if(typeof y === 'undefined'){ y ='World' }
console.log(x,y)
}
log('Hello','') // Hello
ES6允许直接为函数设定默认值,写在参数后面。
function log(x,y = 'World') {
console.log(x,y)
}
log('Hello') // Hello World
参数的默认值不是在定义的时候执行的,而是在运行的时候执行的,如果参数已经赋值,那么默认值就失效了。
函数默认值结合尾递归优化实现阶乘。
function factorial(n, total =1){
if(n ===1)return total
return factorial(n-1,n*total)
}
factorial(5) // 120
十、箭头函数没有自己的this,它的this是引用外层的this。
function foo(){
return () => {
return ()=>{
return ()=>{
console.log('id:',this.id)
}
}
}
}
let f = foo.call({id: 1})
let t1 = f.call({id:2})()() // id: 1
let t2 = f().call({id: 3})() // id: 1
let t3 = f()().call({id: 4}) // id: 1
上述代码中只有一个this,那就是foo的this,内层三个箭头函数的this就是foo的this。箭头函数使用call()、apply()和bind()这些方法也不能改变this的指向。
重要参考: 阮一峰 ES6教程 - 网道