美文网首页
Understanding ECMAScript6(上)

Understanding ECMAScript6(上)

作者: Michael_lpf | 来源:发表于2017-02-16 22:38 被阅读0次


引言

写下这一系列关于 ES6 笔记要从《Understanding ECMA6》 这本书说起。
我在网上找到了 中译版,拜读了一下(对译者感激不尽!)。
读过了书当然要整理一下知识,于是就有了这篇笔记。

先看 Scott 老师的大宝剑🗡,简单阐述了 ES6 的实用新特性👇


Paste_Image.png

我们慢慢道来。。。


Part 1: 块级绑定(块级作用域)


const 声明
  • 使用 const 声明被认为是一个常量声明,在设置初始值后便不能被更改。
    正因如此,const 声明后必须进行初始化。
    没有初始化的结果是语法错误👇
Paste_Image.png
  • const 会阻止对变量自身值的修改,但当使用 const 声明一个对象时,对象内部的值是可以更改的👇
Paste_Image.png
let 声明和“暂时性死区”
  • 基本上可以用 let 声明代替 var 声明。但要注意,let 声明不会被提升,一般要手动写在作用域的顶部,以供整个代码块使用。
  • 使用 const 和 let 声明变量时,试图在声明前访问会导致引用错误,即是是 typeof() 这样普遍被认为安全的访问👇
Paste_Image.png

JS 引擎面对 var 声明会将其提升至顶,而面对 const 和 let 则会将其置于“暂时性死区”,在死区内访问变量都会导致错误。上面第3、4行代码不会执行的。
但若在块外访问变量,则只会返回一个可能和预期不一样的结果而已,不至于报错。

Paste_Image.png
循环内的函数
  • 以下代码并未返回我们预期的结果👇
Paste_Image.png

这是因为循环内对 i 的引用是共享的,意味着循环内定义的函数是对同一个变量(循环结束时的值)的引用。
我们使用立即执行函数修复这个问题👇

Paste_Image.png

如今使用 let 声明循环中的变量可以达到同样的效果,更简洁👇

Paste_Image.png

这是因为每次循环,都创建一个变量绑定,每个函数拥有了变量的副本,于是输出不同的值。


不添加属性到全局对象

let 和 const 声明全局变量/常量时,并非会在全局对象上添加属性,这与 var 声明完全不同👇

Paste_Image.png
块级作用域最佳实践
  • 老思路是:普遍使用 let 代替 var 声明,当需要声明一个需要保护的变量时使用 const。
  • 新思路是:普遍使用 const 声明,只有当确定变量需要被更改的时候使用 let(依据是大部分变量初始化后不需要被修改,而意料外的改动是BUG源头之一)。


Part 2: 函数


参数默认值
  • ES6 中参数默认值的使用大致如下👇
Paste_Image.png

只有当参数未传递👇


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 这样的语法可以用来创建剩余参数👇
Paste_Image.png
  • ES6 中的函数构造器被增强了。
    上面两个同样作为 ES6 新特性的 “剩余参数” 和 “参数默认值” 自然也在新的函数构造器中得到了支持👇
Paste_Image.png

一个返回第一个剩余参数的例子👇

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 对象👇
Paste_Image.png
  • 没有 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 中不再对其检查,无论是否声明严格模式。

Paste_Image.png

👆 同名属性后者的值会覆盖前者。


明确的对象属性枚举顺序

ES5 没有明确的对象属性枚举顺序,各 JS 引擎厂商未必统一。
ES6 中对此作了定义:数字键总是在前,以升序排列;之后分别是字符串和符号键按添加顺序排列。

Paste_Image.png
修改对象的原型
  • ES5 中通过构造器或 Object.create() 来指定新建对象的原型。
    ES6 通过 setPrototypeOf() 方法改变指定对象的原型。
    接收两个参数:待修改原型的对象,将成为前者原型的对象👇
Paste_Image.png Paste_Image.png

Part 4: 解构:方便的数据访问


对象解构

在 ES5 中从对象中取值👇

Paste_Image.png

ES6 解构语法👇

Paste_Image.png

使用结构器,必须初始化,否则有语法错误👇

Paste_Image.png

也可以先声明,后解构赋值。
但要将表达式写在一个圆括号中(避免被 JS 引擎解析为代码块)👇

Paste_Image.png

当变量没有在对象中找到同名属性的时候,无意外,它会被赋值 undefined👇

Paste_Image.png

当然也可以在解构中使用默认值,就像函数的参数默认值一样👇

Paste_Image.png

一定要将本地变量和对象属性名设置成一样的吗?这样不够灵活。当然不是👇

Paste_Image.png

👆不过这里的语法有些新颖,与传统对象字面量语法相反。
被赋值的本地变量书写在冒号之后,而真正的值(此处是对象属性值)则书写在冒号之前。

嵌套的对象结构:
嵌套的对象结构适用于层级深一些的对象。

Paste_Image.png
数组解构

与对象解构非常相似,只是不存在同名、不同名的对接方法。
赋值的顺序由原数组顺序决定👇

Paste_Image.png

可以有意忽略若干项,使用 , 来占位👇

Paste_Image.png

同样可以有默认值👇

Paste_Image.png

同样可以先声明,后解构赋值。
而且不必将表达式写在圆括号中👇

Paste_Image.png

嵌套的数组解构,使用 [] 下潜到数组深层👇

Paste_Image.png

剩余项,和函数的参数剩余项又很类似,使用 ... 接收数组解构赋值的剩余项目👇

Paste_Image.png

数组剩余项解构在生产中有个很常用的技巧:克隆数组。

Paste_Image.png

本节完
Understanding ECMAScript6(中)
Understanding ECMAScript6(下)

相关文章

网友评论

      本文标题:Understanding ECMAScript6(上)

      本文链接:https://www.haomeiwen.com/subject/ipqtwttx.html