ES6學習筆記(三)【函式,物件】

風靈使發表於2019-04-05

簡介

ES6對函式的擴充套件比較多,主要有三點:新的書寫方式,引數,擴充套件運算子

另外還有關於嚴格模式和效能優化的變動,初學者暫時可以跳過這些,這裡不做詳細說明

這一章節的知識點非常重要,可能是ES6中最常用的知識點之一

正文

ES6中我們可以使用“箭頭”(=>)定義函式。

var f = v => v

箭頭左側是引數,右側是函式要執行的程式碼

如果要執行的程式碼只有一條語句,這條語句的執行結果就是函式的返回值,上面的例子相當於:

var f = function(v) {
  return v
}

如果箭頭函式的程式碼塊部分多於一條語句,就必須使用大括號將它們括起來,並使用return語句返回。

如果箭頭函式的引數不是一個(沒有引數或大於一個),需要使用一個圓括號包裹引數

(num1, num2) => {
  let num3 = 3
  return num1 + num2 + num3
}

需要注意的是,箭頭函式沒有arguments物件

並且箭頭函式內部的this被繫結為它定義時所在的物件,而不是隨著呼叫方式不同而改變

箭頭函式中取消了arguments物件,是因為ES6中有了更好的替代方式:擴充套件運算子

之前我們在陣列一節提到過擴充套件運算子,用來展開一個可遍歷的物件

如果擴充套件運算子寫在函式的引數中,則稱作rest引數,是擴充套件運算子的逆運算

let foo = (...values) => console.log(values)
foo(1, 2, 3)
// [1, 2, 3]

顯然我們輸入的引數是逗號分隔的序列,被...操作符合成了一個陣列,以此可以替代arguments物件

注意,只有...操作符寫在函式的引數中,才是合併的效果,寫在其他地方都是展開的效果

let foo = (...values) => console.log(...values)
foo(1, 2, 3)
// 1 2 3 

顯然引數中的...把引數合併為一個陣列,函式程式碼塊中的...又把陣列展開為逗號分隔序列

注意在console.log方法中,逗號將列印為空格,所以你不會在輸出中看見逗號

在ES6中,我們可以直接給函式引數設定預設值

let log = (x, y = 'World') => console.log(x, y)

log('Hello') // Hello World
log('Hello', 'China') // Hello China
log('Hello', '') // Hello

注意這種預設值的宣告方式與let類似,函式程式碼塊中不能用letconst再次宣告同一個引數

let foo = (x = 5) => {
  let x = 1  // error
  const x = 2  // error
}

思考

這部分內容希望你都可以手動敲一遍,獨立思考

如果箭頭函式要返回一個物件,可以這樣簡寫嗎?

var getTempItem = id => { id: id, name: "Temp" }

如何改正寫法?


箭頭函式書寫的都是匿名函式,用來寫回撥函式特別簡潔

試著用箭頭函式改寫常用的引數包含回撥函式的方法,比如:

// 普通函式寫法
[1, 2, 3].map(function (x) {
  return x * x
})

// 箭頭函式寫法
[1, 2, 3].map(x => x * x)

如果箭頭函式內部巢狀箭頭函式怎麼寫?


試著寫出一個例子說明箭頭函式的this與普通函式的this的不同


let foo = (a, ...b, c) => console.log(a, b, c)

執行結果是什麼? 試著猜測為什麼會這樣


let foo = (x = 5) => {
  var x = 1
  let x = 1
}
foo()

先不執行這段程式碼,猜測它會在哪一行報錯?

對於這段程式碼的執行結果,試著想出一個自己滿意的解釋


ES6對於物件的擴充套件不多,只有一些常用的簡潔寫法和一些新增API

在ES8中新增了物件的擴充套件運算子 ... 不過我們可以在Babel轉譯後使用它

正文

ES6中,物件的屬性可以使用簡潔表示法來簡寫

let foo = 'bar'

let baz = {foo}
// 等同於
let baz = {foo: foo}
let obj = {
  method () {}
}
// 等同於
let obj = {
  method: () => {}
}

上面例子表明,在物件中,可以直接寫變數,屬性名為變數名, 屬性值為變數的值,方法也同理

ES6中,物件的屬性名可以使用表示式

let obj = {
  ['a' + 'bc']: 123,
  ['h' + 'ello']() {
    return 'hello world!';
  }
}
console.log(obj.abc)
// 123
console.log(obj.hello())
// hello world!

很好理解,js解析器會先執行屬性名錶達式,得到的結果作為真正的屬性名,這個表示式必須用方括號包裹

ES6物件中新增了一些API,正常工作中用到的很少,這裡只介紹兩個最常見的

Object.assign 方法用於物件的合併,接收的引數是任意個物件,會依次把第2,3,4…個物件

合併到第一個物件上,如果有重複的屬性名,後來的會覆蓋先前的。

let target = { a: 1, b: 1 }
let source1 = { b: 2, c: 2 }
let source2 = { c: 3 }

Object.assign(target, source1, source2);
target // {a:1, b:2, c:3}

Object.is 方法用於判斷兩個值是否相等

以前我們判斷兩個值相等可以用=====

不過==會發生隱式轉換,===無法判斷NaN

Object.is===不同之處只有兩個:一是+0不等於-0,二是NaN等於自身。

+0 === -0 //true
NaN === NaN // false

Object.is(+0, -0) // false
Object.is(NaN, NaN) // true

ES8中將會支援物件的擴充套件運算子,這是一個還未釋出的版本

不過我們早已可以使用Babel轉譯來使用它,並且在工作中也經常用到

let z = { a: 3, b: 4 }
let n = { ...z }
n // { a: 3, b: 4 }

注意這段程式碼無法在瀏覽器執行,目前沒有瀏覽器支援ES8

物件的擴充套件運算子通常和解構賦值配合使用,關於解構賦值,我們會在後面的章節介紹

思考

這部分內容希望你都可以手動敲一遍,獨立思考

const keyA = {a: 1}
const keyB = {b: 2}

const obj = {
  [keyA]: 'aaa',
  [keyB]: 'bbb'
}

輸出一下obj,並試著解釋這個結果


Object.assign可以拷貝原型鏈上繼承來的屬性嗎?可以拷貝不可列舉的屬性嗎?

for...in可以遍歷原型鏈上繼承來的屬性嗎?可以遍歷不可列舉的屬性嗎?

相關文章