天天看點

ES6筆記-文法拓展ES6變量方面的拓展

ES6筆記

  • ES6變量方面的拓展
    • 1 let和const指令
      • 1.1 暫時性死區
    • 2 塊級作用域與函數聲明
    • 3 const
    • 4 變量的解構指派
      • 4.1數組的解析指派
      • 4.2 對象的解析指派
      • 4.3字元串的解構指派
      • 4.4 用途

ES6變量方面的拓展

1 let和const指令

let聲明的變量不會發生變量提升

// var 的情況
console.log(foo); // 輸出undefined
var foo = 2;

// let 的情況
console.log(bar); // 報錯ReferenceError
let bar = 2;
           

1.1 暫時性死區

var tmp = 123;

if (true) {
  tmp = 'abc'; // ReferenceError
  let tmp;
}
           

在if{}作用域内,對tmp在聲明前指派會報錯

這意味着typeof不在是一個百分之百安全的操作,在let變量聲明前使用typeof就會抛出ReferenceError

作為比較,如果一個變量根本沒有被聲明,使用typeof反而不會報錯。

typeof undeclared_variable // "undefined"
           

有些死區太隐蔽不容易發現

function bar(x = 2, y = x) {
  return [x, y];
}
bar(); // [2, 2]

// 不報錯
var x = x;

// 報錯
let x = x;
// ReferenceError: x is not defined
           

2 塊級作用域與函數聲明

// 浏覽器的 ES6 環境
function f() { console.log('I am outside!'); }

(function () {
  if (false) {
    // 重複聲明一次函數f
    function f() { console.log('I am inside!'); }
  }

  f();
}());
// Uncaught TypeError: f is not a function
           

ES5會輸出 I am inside

ES6會報錯

-允許在塊級作用域内聲明函數。

-函數聲明類似于var,即會提升到全局作用域或函數作用域的頭部。

-同時,函數聲明還會提升到所在的塊級作用域的頭部。

注意,上面三條規則隻對 ES6 的浏覽器實作有效,其他環境的實作不用遵守,還是将塊級作用域的函數聲明當作let處理。

盡量避免在塊級作用域聲明函數,如果确實需要應該寫成函數表達式

// 塊級作用域内部的函數聲明語句,建議不要使用
{
  let a = 'secret';
  function f() {
    return a;
  }
}

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

3 const

const除了指向的對象或資料不能改變外(指向的對象裡的資料可以改變),其他性質與let相同

如果真想當機對象,用Object.freeze()方法

const foo = Object.freeze({});

// 正常模式時,下面一行不起作用;
// 嚴格模式時,該行會報錯
foo.prop = 123;

           

除了将對象本身當機,對象的屬性也應該當機。下面是一個将對象徹底當機的函數。

var constratize = (obj) => {
	Object.freeze(obj);
	Object.keys(obj).forEach((key,i)=>{
		if(typeof obj[key] === 'object'){
			constratize(obj[key]);
		}
	});
}
           

4 變量的解構指派

4.1數組的解析指派

let [a, b, c] = [1, 2, 3];

let [foo, [[bar], baz]] = [1, [[2], 3]];
foo // 1
bar // 2
baz // 3

let [ , , third] = ["foo", "bar", "baz"];
third // "baz"

let [x, , y] = [1, 2, 3];
x // 1
y // 3

let [head, ...tail] = [1, 2, 3, 4];
head // 1
tail // [2, 3, 4]

let [x, y, ...z] = ['a'];
x // "a"
y // undefined
z // []
           

如果解構不成功,變量的值就等于undefined。

允許指定預設值

let [foo = true] = [];
foo // true

let [x, y = 'b'] = ['a']; // x='a', y='b'
let [x, y = 'b'] = ['a', undefined]; // x='a', y='b'
           

注意,ES6 内部使用嚴格相等運算符(===),判斷一個位置是否有值。是以,隻有當一個數組成員嚴格等于undefined,預設值才會生效。

4.2 對象的解析指派

對象的解構與數組有一個重要的不同。數組的元素是按次序排列的,變量的取值由它的位置決定;而對象的屬性沒有次序,順序不影響取值,變量必須與屬性同名,才能取到正确的值。

解構失敗,undefined

let { bar, foo } = { foo: 'aaa', bar: 'bbb' };
foo // "aaa"
bar // "bbb"

let { baz } = { foo: 'aaa', bar: 'bbb' };
baz // undefined

           

把現有對象指派到某個變量

// 例一
let { log, sin, cos } = Math;

// 例二
const { log } = console;
log('hello') // hello
           

對象嵌套解構

let obj = {
  p: [
    'Hello',
    { y: 'World' }
  ]
};

let { p, p: [x, { y }] } = obj;
x // "Hello"
y // "World"
p // ["Hello", {y: "World"}]


           
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}
           

上面代碼有三次解構指派,分别是對loc、start、line三個屬性的解構指派。注意,最後一次對line屬性的解構指派之中,隻有line是變量,loc和start都是模式,不是變量。

對已經聲明的變量進行解構

// 錯誤的寫法
let x;
{x} = {x: 1};
// SyntaxError: syntax error

// 正确的寫法
let x;
({x} = {x: 1});
           

上面代碼的寫法會報錯,因為 JavaScript 引擎會将{x}了解成一個代碼塊,進而發生文法錯誤。隻有不将大括号寫在行首,避免 JavaScript 将其解釋為代碼塊,才能解決這個問題。

4.3字元串的解構指派

字元串也可以解構指派。這是因為此時,字元串被轉換成了一個類似數組的對象。

const [a, b, c, d, e] = 'hello';
a // "h"
b // "e"
c // "l"
d // "l"
e // "o"

let {length : len} = 'hello';
len // 5
           

解構指派的規則是,隻要等号右邊的值不是對象或數組,就先将其轉為對象。由于undefined和null無法轉為對象,是以對它們進行解構指派,都會報錯。

4.4 用途

1)交換變量的值

let x = 1;
let y = 2;

[x, y] = [y, x];```
2)從函數傳回多個值

```javascript
// 傳回一個數組

function f([x,y,z]){...}
f([1,2,3]);

// 傳回一個對象

function example() {
	return{
		foo:1,
		bar:2
	};
}
           

3)函數參數的定義

//參數是一組有次序的值
function f([x,y,z]){...}
f([1,2,3]);
           

4)提取JSON資料

解構指派對提取JSON對象中的資料,尤其有用。

let jsonData = {
	id:42,
	status:"OK",
	data:[867,5309]
};

let {id,status,data:number} = jsonData;
           

5)函數參數的預設值

這個不太懂

6)周遊Map結構

任何部署了Iterator接口的對象,都可以用for…of循環周遊

//對一個map的定義省略
for (let [key,value] of map){
	console.log(key+"is"+value);
}
           

如果隻想擷取鍵名,或者隻想擷取鍵值,可以寫成下面這樣。

for(let [key] of map){}
for(let [,value] of map){}
           

7)輸入子產品的指定方法

加載子產品時,往往需要指定輸入哪些方法。解構指派使得輸入語句非常清晰。

不太懂

繼續閱讀