引言
写下这一系列关于 ES6 笔记要从《Understanding ECMA6》 这本书说起。
我在网上找到了 中译版,拜读了一下(对译者感激不尽!)。
读过了书当然要整理一下知识,于是就有了这篇笔记。
先看 Scott 老师的大宝剑🗡,简单阐述了 ES6 的实用新特性👇
Paste_Image.png
我们慢慢道来。。。
Part 1: 块级绑定(块级作用域)
const 声明
- 使用 const 声明被认为是一个常量声明,在设置初始值后便不能被更改。
正因如此,const 声明后必须进行初始化。
没有初始化的结果是语法错误👇
- const 会阻止对变量自身值的修改,但当使用 const 声明一个对象时,对象内部的值是可以更改的👇
let 声明和“暂时性死区”
- 基本上可以用 let 声明代替 var 声明。但要注意,let 声明不会被提升,一般要手动写在作用域的顶部,以供整个代码块使用。
- 使用 const 和 let 声明变量时,试图在声明前访问会导致引用错误,即是是 typeof() 这样普遍被认为安全的访问👇
JS 引擎面对 var 声明会将其提升至顶,而面对 const 和 let 则会将其置于“暂时性死区”,在死区内访问变量都会导致错误。上面第3、4行代码不会执行的。
但若在块外访问变量,则只会返回一个可能和预期不一样的结果而已,不至于报错。
循环内的函数
- 以下代码并未返回我们预期的结果👇
这是因为循环内对 i 的引用是共享的,意味着循环内定义的函数是对同一个变量(循环结束时的值)的引用。
我们使用立即执行函数修复这个问题👇
如今使用 let 声明循环中的变量可以达到同样的效果,更简洁👇
Paste_Image.png这是因为每次循环,都创建一个变量绑定,每个函数拥有了变量的副本,于是输出不同的值。
不添加属性到全局对象
let 和 const 声明全局变量/常量时,并非会在全局对象上添加属性,这与 var 声明完全不同👇
Paste_Image.png块级作用域最佳实践
- 老思路是:普遍使用 let 代替 var 声明,当需要声明一个需要保护的变量时使用 const。
- 新思路是:普遍使用 const 声明,只有当确定变量需要被更改的时候使用 let(依据是大部分变量初始化后不需要被修改,而意料外的改动是BUG源头之一)。
Part 2: 函数
参数默认值
- ES6 中参数默认值的使用大致如下👇
只有当参数未传递👇
Paste_Image.png
或是指定参数为 undefined 时👇
Paste_Image.png默认参数值才会被使用。
参数默认值对 arguments 对象的影响
在 ES5 非严格模式下,arguments 对象会更新自己以反映参数的变化👇
Paste_Image.png在 ES5 严格模式下,为打消混乱,arguments 对象不再更新👇
Paste_Image.png在使用了 ES6 默认参数值的函数中,arguments 对象的表现和严格模式下的表现一致(无论是否声明了严格模式)👇
Paste_Image.png(👆上面例子中第二个 console.log 输出 false,是因为调用是没有传入参数 b,此时 b 为 2,arguments[1] 为 undefined。)
至此,我们也就可用 arguments 来了解参数的初始状态了。
参数默认值表达式
- 可以将前面的参数作为后面的参数的默认值👇
function foo(first, second = first){
return first + second
}
如此,调用时可以只传一个实参了foo(1) //2
,乍看没什么生产用途。
不急,还可以将前面的参数传递给一个函数来产生后面的参数👇
function increase(val){
return val + 5;
}
function foo(first, second = increase(first)){
return first + second
}
foo(1); // 7
-
仅允许前面的参数作为后面参数的默认值,反之是行不通的。
这是因为默认参数在函数初次调用时被初始化,为 p1 赋值为 p2 时,p2 还没有被初始化呢👇
Paste_Image.png
剩余参数
- 类似
...restArgs
这样的语法可以用来创建剩余参数👇
- ES6 中的函数构造器被增强了。
上面两个同样作为 ES6 新特性的 “剩余参数” 和 “参数默认值” 自然也在新的函数构造器中得到了支持👇
一个返回第一个剩余参数的例子👇
Paste_Image.png箭头函数
- 总览:
- 箭头函数被设计用来代替匿名函数表达式。
- 拥有更简洁的语法。
- 没有 arguments 对象。
- 不能修改 this 绑定。
- 箭头函数在语法层面有很多变体,但所有变体都以参数开头,接一个箭头
=>
,而后是函数体。
当函数只有一个参数,不需要任何语法。随后是函数体,函数体会被返回,即使没有return
👇
var foo = val => val;
// 等同于
var foo = function(val){
return val;
}
当函数多于一个参数,需要圆括号将参数括起来👇
var add = (a, b) => a + b;
// 等同于
var add = function(a, b){
return a + b;
}
若函数没有参数,那么必须使用一对空圆括号👇
var foo = () => true;
// 等同于
var foo = function(){
return true;
}
当函数包含多个语句时,需要花括号括起来,并明确 return
👇
var cal = (a, b) => { a++; return a + b}
// 等同于
var cal = function(a, b){
a++
return a + b;
}
如果函数内需要返回对象字面量,则需要用圆括号括起来👇
var getObj = () => ({ name:'Nick', age:30});
// 等同于
var getObj = function(){
return {
name:'Nick',
age:30
}
}
- 创建立即调用函数
传统的立即调用函数,有两种书写方法,圆括号是否包裹 “参数调用” 部分都可以👇
// 一个立即调用函数
var person1 = (function(name){
return {
getName: function(){
return name
}
}
})('Nick');
// 另一个立即调用函数
var person2 = (function(name){
return {
getName: function(){
return name;
}
}
}('Penny'));
但使用箭头函数时,圆括号只需包裹函数体,不要包裹 “参数调用” 部分👇
let person3 = ((name) => {
return {
getName: function(){
return name;
}
}
})('Marvin');
- 没有 arguments 对象👇
- 没有 this 绑定
函数内部的 this 可以被更改,这取决于调用时的上下文。
而箭头函数没有 this 绑定。如果箭头函数包含于一个非箭头函数内,那么 this 值就与该函数相等。否则 this 值就是 undefined。
Part 3: 扩展的对象功能
属性速记和方法简写
- 当对象属性名和本地变量名时,可以简写👇
// ES5
function person(name, age){
return {
name: name,
age: age
}
}
// ES6 属性速记
function person(name, age){
return {
name,
age
}
}
当只有属性名时,JS 引擎会查找周边作用域中同名的变量,若找到,改变量的值会赋给同名属性。
- 省略冒号和 function 关键字,可以简写方法👇
// ES5
var personA = {
name: 'Noviziki',
getName: function(){
console.log(this.name);
}
}
// ES6简写
var personB = {
name: 'Ragger',
gerName(){
console.log(this.name);
}
}
重复的对象字面量属性
在 ES5 严格模式中,重复定义的对象属性是会造成语法错误的。
在 ES6 中不再对其检查,无论是否声明严格模式。
👆 同名属性后者的值会覆盖前者。
明确的对象属性枚举顺序
ES5 没有明确的对象属性枚举顺序,各 JS 引擎厂商未必统一。
ES6 中对此作了定义:数字键总是在前,以升序排列;之后分别是字符串和符号键按添加顺序排列。
修改对象的原型
- ES5 中通过构造器或
Object.create()
来指定新建对象的原型。
ES6 通过setPrototypeOf()
方法改变指定对象的原型。
接收两个参数:待修改原型的对象,将成为前者原型的对象👇
Part 4: 解构:方便的数据访问
对象解构
在 ES5 中从对象中取值👇
Paste_Image.pngES6 解构语法👇
Paste_Image.png使用结构器,必须初始化,否则有语法错误👇
Paste_Image.png也可以先声明,后解构赋值。
但要将表达式写在一个圆括号中(避免被 JS 引擎解析为代码块)👇
当变量没有在对象中找到同名属性的时候,无意外,它会被赋值 undefined👇
Paste_Image.png当然也可以在解构中使用默认值,就像函数的参数默认值一样👇
Paste_Image.png一定要将本地变量和对象属性名设置成一样的吗?这样不够灵活。当然不是👇
Paste_Image.png👆不过这里的语法有些新颖,与传统对象字面量语法相反。
被赋值的本地变量书写在冒号之后,而真正的值(此处是对象属性值)则书写在冒号之前。
嵌套的对象结构:
嵌套的对象结构适用于层级深一些的对象。
数组解构
与对象解构非常相似,只是不存在同名、不同名的对接方法。
赋值的顺序由原数组顺序决定👇
可以有意忽略若干项,使用 ,
来占位👇
同样可以有默认值👇
Paste_Image.png同样可以先声明,后解构赋值。
而且不必将表达式写在圆括号中👇
嵌套的数组解构,使用 []
下潜到数组深层👇
剩余项,和函数的参数剩余项又很类似,使用 ...
接收数组解构赋值的剩余项目👇
数组剩余项解构在生产中有个很常用的技巧:克隆数组。
Paste_Image.png本节完
Understanding ECMAScript6(中)
Understanding ECMAScript6(下)
网友评论