1. 程式人生 > >[ ES6 ](二)函式陣列物件擴充套件

[ ES6 ](二)函式陣列物件擴充套件

函式的擴充套件

函式引數的預設值

ES5:
function log(x, y) {
  y = y || 'World';
  console.log(x, y);
}

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

ES6:
function Point(x = 0, y = 0) {
  this.x = x;
  this.y = y;
}

const p = new Point();
p // { x: 0, y: 0 }


function foo(x = 5, y = 6) {
  console.log(x, y);
}

foo(undefined, null)
// 5 null

作用域

var x = 1;
function foo(x, y = function() { x = 2; }) {
  x = 3;
  y();
  console.log(x);
}

foo() // 2
x // 1

箭頭函式 ***

// 報錯
let getTempItem = id => { id: id, name: "Temp" };

// 不報錯
let getTempItem = id => ({ id: id, name: "Temp" });

使用注意點

箭頭函式有幾個使用注意點。 (1)函式體內的this物件,就是定義時所在的物件,而不是使用時所在的物件。

(2)不可以當作建構函式,也就是說,不可以使用new命令,否則會丟擲一個錯誤。。 (3)不可以使用arguments物件,該物件在函式體內不存在。如果要用,可以用 rest 引數代替。。 (4)不可以使用yield命令,因此箭頭函式不能用作 Generator 函式。

箭頭函式可以讓setTimeout裡面的this,繫結定義時所在的作用域,而不是指向執行時所在的作用域。下面是另一個例子。

function Timer() {
  this.s1 = 0;
  this.s2 = 0;
  // 箭頭函式
  setInterval(() => this.s1++, 1000);
  // 普通函式
  setInterval(function () {
    this.s2++;
  }, 1000);
}

var timer = new Timer();

setTimeout(() => console.log('s1: ', timer.s1), 3100);
setTimeout(() => console.log('s2: ', timer.s2), 3100);
// s1: 3
// s2: 0

上面程式碼中,Timer函式內部設定了兩個定時器,分別使用了箭頭函式和普通函式。前者的this繫結定義時所在的作用域(即Timer函式),後者的this指向執行時所在的作用域(即全域性物件)。所以,3100 毫秒之後,timer.s1被更新了 3 次,而timer.s2一次都沒更新。

不適用場合

由於箭頭函式使得this從“動態”變成“靜態”,下面兩個場合不應該使用箭頭函式。 第一個場合是定義函式的方法,且該方法內部包括this

const cat = {
  lives: 9,
  jumps: () => {
    this.lives--;
  }
}

上面程式碼中,cat.jumps()方法是一個箭頭函式,這是錯誤的。呼叫cat.jumps()時,如果是普通函式,該方法內部的this指向cat;如果寫成上面那樣的箭頭函式,使得this指向全域性物件,因此不會得到預期結果。

第二個場合是需要動態this的時候,也不應使用箭頭函式。

var button = document.getElementById('press');
button.addEventListener('click', () => {
  this.classList.toggle('on');
});

上面程式碼執行時,點選按鈕會報錯,因為button的監聽函式是一個箭頭函式,導致裡面的this就是全域性物件。如果改成普通函式,this就會動態指向被點選的按鈕物件。

另外,如果函式體很複雜,有許多行,或者函式內部有大量的讀寫操作,不單純是為了計算值,這時也不應該使用箭頭函式,而是要使用普通函式,這樣可以提高程式碼可讀性。

陣列的擴充套件

複製陣列

const a1 = [1, 2];
// 寫法一
const a2 = [...a1];
// 寫法二
const [...a2] = a1;

合併陣列

const a1 = [{ foo: 1 }];
const a2 = [{ bar: 2 }];

const a3 = a1.concat(a2);
const a4 = [...a1, ...a2];

a3[0] === a1[0] // true
a4[0] === a1[0] // true

上面程式碼中,a3和a4是用兩種不同方法合併而成的新陣列,但是它們的成員都是對原陣列成員的引用,這就是淺拷貝。如果修改了原陣列的成員,會同步反映到新陣列。

Array.from()    用於將兩類物件轉為真正的陣列:類似陣列的物件(array-like object)和可遍歷(iterable)的物件
Array.of()  用於將一組值,轉換為陣列
陣列例項的 copyWithin()  在當前陣列內部,將指定位置的成員複製到其他位置(會覆蓋原有成員),然後返回當前陣列
陣列例項的 find() 和 findIndex()    找出第一個符合條件的陣列成員。它的引數是一個回撥函式,所有陣列成員依次執行該回調函式,直到找出第一個返回值為true的成員,然後返回該成員。
陣列例項的 fill()   使用給定值,填充一個數組
陣列例項的 entries(),keys() 和 values()    用於遍歷陣列。它們都返回一個遍歷器物件
陣列例項的 includes()   返回一個布林值,表示某個陣列是否包含給定的值
陣列例項的 flat(),flatMap()    將巢狀的陣列“拉平”,變成一維的陣列。該方法返回一個新陣列,對原資料沒有影響。

物件的擴充套件

Object.is() 用來比較兩個值是否嚴格相等
Object.assign() 用於物件的合併,將源物件(source)的所有可列舉屬性,複製到目標物件(target)/實行的是淺拷貝,而不是深拷貝

屬性的遍歷 ES6 一共有 5 種方法可以遍歷物件的屬性。

(1)for…in

for…in迴圈遍歷物件自身的和繼承的可列舉屬性(不含 Symbol 屬性)。

(2)Object.keys(obj)

Object.keys返回一個數組,包括物件自身的(不含繼承的)所有可列舉屬性(不含 Symbol 屬性)的鍵名。

(3)Object.getOwnPropertyNames(obj)

Object.getOwnPropertyNames返回一個數組,包含物件自身的所有屬性(不含 Symbol 屬性,但是包括不可列舉屬性)的鍵名。

(4)Object.getOwnPropertySymbols(obj)

Object.getOwnPropertySymbols返回一個數組,包含物件自身的所有 Symbol 屬性的鍵名。

(5)Reflect.ownKeys(obj)

Reflect.ownKeys返回一個數組,包含物件自身的所有鍵名,不管鍵名是 Symbol 或字串,也不管是否可列舉。

以上的 5 種方法遍歷物件的鍵名,都遵守同樣的屬性遍歷的次序規則。

首先遍歷所有數值鍵,按照數值升序排列。 其次遍歷所有字串鍵,按照加入時間升序排列。 最後遍歷所有 Symbol 鍵,按照加入時間升序排列。

Object.getOwnPropertyDescriptors()  返回指定物件所有自身屬性(非繼承屬性)的描述物件。
__proto__屬性   用來設定一個物件的prototype物件,返回引數物件本身
Object.setPrototypeOf()     用來設定一個物件的prototype物件,返回引數物件本身
Object.getPrototypeOf()     用於讀取一個物件的原型物件
super 關鍵字        this關鍵字總是指向函式所在的當前物件,關鍵字super,指向當前物件的原型物件。
Object.keys()   ES2017 引入了跟Object.keys配套的Object.values和Object.entries,作為遍歷一個物件的補充手段,供for...of迴圈使用。

let {keys, values, entries} = Object;
let obj = { a: 1, b: 2, c: 3 };

for (let key of keys(obj)) {
  console.log(key); // 'a', 'b', 'c'
}

for (let value of values(obj)) {
  console.log(value); // 1, 2, 3
}

for (let [key, value] of entries(obj)) {
  console.log([key, value]); // ['a', 1], ['b', 2], ['c', 3]
}