1. 程式人生 > 實用技巧 >阮一峰大神ECMAScript 6 入門|筆記整理

阮一峰大神ECMAScript 6 入門|筆記整理

阮一峰大神ECMAScript 6 入門:https://es6.ruanyifeng.com/

let 和 const 命令

  • let宣告的變數只在它所在的程式碼塊有效。

  • 變數ivar命令宣告的,在全域性範圍內都有效,所以全域性只有一個變數i
  • 變數ilet宣告的,當前的i只在本輪迴圈有效,所以每一次迴圈的i其實都是一個新的變數

  • 另外,for迴圈還有一個特別之處,就是設定迴圈變數的那部分是一個父作用域,而迴圈體內部是一個單獨的子作用域。
for (let i = 0; i < 3; i++) {
  let i = 'abc';
  console.log(i);
}
// abc // abc // abc

  • ES6 明確規定,如果區塊中存在letconst命令,這個區塊對這些命令宣告的變數,從一開始就形成了封閉作用域。凡是在宣告之前就使用這些變數,就會報錯。即不存在變數提升。

  • 暫時性死區的本質就是,只要一進入當前作用域,所要使用的變數就已經存在了,但是不可獲取,只有等到宣告變數的那一行程式碼出現,才可以獲取和使用該變數。

  • let不允許在相同作用域內,重複宣告同一個變數。
function func(arg) {
  let arg;        //不能在函式內部重新宣告引數。
}
func() // 報錯

function func(arg) {
  {
    let arg;
  }
}
func() 
// 不報錯

  • 允許在塊級作用域內宣告函式。
  • 函式宣告類似於var,即會提升到全域性作用域或函式作用域的頭部。
  • 同時,函式宣告還會提升到所在的塊級作用域的頭部。
// 塊級作用域內部的函式宣告語句,建議不要使用
{
  let a = 'secret';
  function f() {
    return a;
  }
}

// 塊級作用域內部,優先使用函式表示式
{
  let a = 'secret';
  let f = function () {
    return a;
  };
}

  • const一旦宣告變數,就必須立即初始化,不能留到以後賦值。

  • const
    實際上保證的,並不是變數的值不得改動,而是變數指向的那個記憶體地址所儲存的資料不得改動。

  • ES6 一共有 6 種宣告變數的方法。

var命令和function命令。letconst命令,import命令和class命令。

  • ES6 一方面規定,為了保持相容性,var命令和function命令宣告的全域性變數,依舊是頂層物件的屬性;另一方面規定,let命令、const命令、class命令宣告的全域性變數,不屬於頂層物件的屬性。也就是說,從 ES6 開始,全域性變數將逐步與頂層物件的屬性脫鉤。

  • 全域性環境中,this會返回頂層物件。但是,Node 模組和 ES6 模組中,this返回的是當前模組。
  • 函式裡面的this,如果函式不是作為物件的方法執行,而是單純作為函式執行,this會指向頂層物件。但是,嚴格模式下,這時this會返回undefined

變數的解構賦值

  • ES6 允許按照一定模式,從陣列和物件中提取值,對變數進行賦值,這被稱為解構。
  • 如果解構不成功,變數的值就等於undefined

  • 陣列的元素是按次序排列的,變數的取值由它的位置決定;
  • 而物件的屬性沒有次序,變數必須與屬性同名,才能取到正確的值。

let { foo: baz } = { foo: 'aaa', bar: 'bbb' };
baz // "aaa"
let { foo: baz } = { foo: 'aaa', bar: 'bbb' };
baz // "aaa"
foo // error: foo is not defined
//上面程式碼中,foo是匹配的模式,baz才是變數。真正被賦值的是變數baz,而不是模式foo。
const node = {
  loc: {
    start: {
      line: 1,
      column: 5
    }
  }
};

let { loc, loc: { start }, loc: { start: { line }} } = node;
line // 1
loc  // Object {start: Object}
start // Object {line: 1, column: 5}
// 報錯
let {foo: {bar}} = {baz: 'baz'};
//whywhywhy???
 

  • 物件的解構也可以指定預設值。
var {x = 3} = {};
x // 3

var {x, y = 5} = {x: 1};
x // 1
y // 5

var {x: y = 3} = {};
y // 3

var {x: y = 3} = {x: 5};
y // 5

var { message: msg = 'Something went wrong' } = {};
msg // "Something went wrong"
// 錯誤的寫法
let x;
{x} = {x: 1};
// SyntaxError: syntax error

// 正確的寫法
let x;
({x} = {x: 1});
//只有不將大括號寫在行首,避免 JavaScript 將其解釋為程式碼塊,才能解決這個問題。

  • 字串也可以解構賦值。
const [a, b, c, d, e] = 'hello';
a // "h"
b // "e"
c // "l"
d // "l"
e // "o"

  • 解構賦值的規則是,只要等號右邊的值不是物件或陣列,就先將其轉為物件。由於undefinednull無法轉為物件,所以對它們進行解構賦值,都會報錯。

  • 函式也可以解構賦值。
[[1, 2], [3, 4]].map(([a, b]) => a + b);
// [ 3, 7 ]

  • 不得使用圓括號的情況
    • 變數宣告語句
    • 函式引數
    • 賦值語句的模式
//以下三種模式全部報錯
let [(a)] = [1];
let {x: (c)} = {};

function f([(z)]) { return z; }

({ p: a }) = { p: 42 };
([a]) = [5];

  • 只有賦值語句的非模式部分,可以使用圓括號。
[(b)] = [3]; // 正確
({ p: (d) } = {}); // 正確
[(parseInt.prop)] = [3]; // 正確

  • 變數的解構賦值用途
    • 交換變數的值
    • 從函式返回多個值
      • 函式如果要返回多個值,只能將它們放在陣列或物件裡返回。
    • 函式引數的定義
      • 方便地將一組引數與變數名對應起來。
    • 提取 JSON 資料
    • 函式引數的預設值review
    • 遍歷 Map 結構
      • 任何部署了 Iterator 介面的物件,都可以用for...of迴圈遍歷。
      • Map 結構原生支援 Iterator 介面,配合變數的解構賦值,獲取鍵名和鍵值就非常方便。
    • 輸入模組的指定方法 review
//交換變數
let x = 1;
let y = 2;
[x, y] = [y, x];

// 返回一個物件
function example() {
  return {
    foo: 1,
    bar: 2
  };
}
let { foo, bar } = example();

//提取 JSON 物件中的資料
let jsonData = {
  id: 42,
  status: "OK",
  data: [867, 5309]
};
let { id, status, data: number } = jsonData;

//遍歷 Map 結構
const map = new Map();
map.set('first', 'hello');
map.set('second', 'world');
for (let [key, value] of map) {
  console.log(key + " is " + value);
}
// first is hello
// second is world

// 獲取鍵名
for (let [key] of map) {
  // ...
}

// 獲取鍵值
for (let [,value] of map) {
  // ...
}

字串的拓展

模板字串

  • 用反引號(`)標識。它可以當作普通字串使用,也可以用來定義多行字串,或者在字串中嵌入變數。
  • 如果在模板字串中需要使用反引號,則前面要用反斜槓轉義。
  • 所有模板字串的空格和換行,都是被保留的,可以使用trim方法消除它。
  • 模板字串中嵌入變數,需要將變數名寫在${}之中。
  • 模板字串之中還能呼叫函式。
  • 如果模板字串中的變數沒有宣告,將報錯。
$('#result').append(`
  There are <b>${basket.count}</b> items
   in your basket, <em>${basket.onSale}</em>
  are on sale!
`);

let greeting = `\`Yo\` World!`;

$('#list').html(`
<ul>
  <li>first</li>
  <li>second</li>
</ul>
`.trim());

function fn() {
  return "Hello World";
}

`foo ${fn()} bar`
// foo Hello World bar

例項:模板編譯看不懂

標籤模板 看不懂

字串的新增方法

String.raw()

  • 該方法返回一個斜槓都被轉義(即斜槓前面再加一個斜槓)的字串
  • 如果原字串的斜槓已經轉義,那麼String.raw()會進行再次轉義。
String.raw`Hi\n${2+3}!`
// 實際返回 "Hi\\n5!",顯示的是轉義後的結果 "Hi\n5!"

//why why why?
// `foo${1 + 2}bar`
// 等同於
String.raw({ raw: ['foo', 'bar'] }, 1 + 2) // "foo3bar"
 

確定一個字串是否包含在另一個字串中

  • includes():返回布林值,表示是否找到了引數字串。
  • startsWith():返回布林值,表示引數字串是否在原字串的頭部。
  • endsWith():返回布林值,表示引數字串是否在原字串的尾部。

repeat()

返回一個新字串,表示將原字串重複n

引數如果是小數,會被取整。

引數是負數或者Infinity,會報錯。

引數是 0 到-1 之間的小數,則等同於 0,這是因為會先進行取整運算。
引數NaN等同於 0。

引數是字串,則會先轉換成數字。

'x'.repeat(3) // "xxx"
'hello'.repeat(2) // "hellohello"
'na'.repeat(2.9) // "nana"
'na'.repeat(-0.9) // ""
'na'.repeat(NaN) // ""

//why why why?
'na'.repeat('na') // ""
'na'.repeat('3') // "nanana"

padStart(),padEnd()

  • 如果某個字串不夠指定長度,會在頭部或尾部補全。padStart()用於頭部補全,padEnd()用於尾部補全。
  • 如果原字串的長度,等於或大於最大長度,則字串補全不生效,返回原字串。
  • 如果省略第二個引數,預設使用空格補全長度。
'x'.padStart(4, 'ab') // 'abax'
'x'.padEnd(5, 'ab') // 'xabab'

'xxx'.padStart(2, 'ab') // 'xxx'

'x'.padStart(4) // '   x'
'x'.padEnd(4) // 'x   '
 

trimStart(),trimEnd()

  • trimStart()消除字串頭部的空格,trimEnd()消除尾部的空格。
  • 它們返回的都是新字串,不會修改原始字串。
const s = '  abc  ';

s.trim() // "abc"
s.trimStart() // "abc  "
s.trimEnd() // "  abc"

matchAll()

  • 返回一個正則表示式在當前字串的所有匹配