[譯] 一些ES6的小技巧

原文: Check out these useful ECMAScript 2015 (ES6) tips and tricksjavascript

有任何錯誤請在評論指出,感激涕零。html

EcmaScript 2015 (ES6) 已經出現了不少年了,咱們可使用它的一些新特性。java

1.設置必須的函數參數

ES6 提供了 默認的參數值,可讓你在函數的參數中指定默認值當參數沒有傳遞其值的時候。es6

const required = () => {throw new Error('Missing parameter')};
//The below function will trow an error if either "a" or "b" is missing.
const add = (a = required(), b = required()) => a + b;
add(1, 2) //3
add(1) // Error: Missing parameter.
複製代碼

在這個例子中,咱們對函數 add 的參數 ab 設置了一個默認值,這個默認值爲一個函數。當函數 add 被執行時,且參數 ab 有一個沒有傳遞值的時候,這個 required 函數就會執行,咱們就會獲得一個報錯 Error: Missing parameter.數組

2.很是強力的"reduce"

Array 的方法 reduce 是一個有很是多用處的函數。 它一個很是具備表明性的做用是將一個數組轉換成一個值。可是你能夠用它來作更多的事。promise

🔥 Tip: 這些小技巧的的初始值都是一個數組或者一個對象而不是一個像字符串之類的簡單的值閉包

2.1 使用reduce作到同時有map和filter的做用

假設有這樣的一個場景,你有一個list,裏面有一些item, 你須要更新這些item, 更新完之後你須要使用filter來過濾掉你不須要的item。可是這樣的話你須要遍歷這個數組兩次!ecmascript

const numbers = [10, 20, 30, 40];
const doubledOver50 = numbers.reduce((finalList, num) => {
  
  num = num * 2; //double each number (i.e. map)
  
  //filter number > 50
  if (num > 50) {
    finalList.push(num);
  }
  return finalList;
}, []);
doubledOver50; // [60, 80]
複製代碼

在這個例子裏面,咱們想要讓數組裏面的值翻倍,而後咱們只想要裏面大於 50 的元素。注意一下咱們是如何使用 reduce 方法作到同時有讓元素的值翻倍,而後過濾的。async

2.2 使用"reduce"代替"map"和"filter"

在原文中沒有體現這部分代碼,只說了注意2.1的代碼。在這裏我添加一下這部分代碼:函數

2.2.1 使用"reduce"代替"map"
function map(arr, exec) {
    var res = arr.reduce((res, item, index) => {
        var newItem = exec(item, index)
        res.push(newItem)
        return res
    }, [])
    return res
}

[1, 2, 3].map((item) => item * 2) // [2, 4, 6]

map([1, 2, 3], item => item * 2) // [2, 4, 6]
複製代碼
2.2.2 使用"reduce"代替"filter"
function filter(arr, exec) {
    var res = arr.reduce((res, item, index) => {
        if (exec(item, index)) {
            res.push(item)
        }
        return res
    }, [])
    return res
}

[1, 2, 3].filter((item, index) => index < 2) // [1, 2]
filter([1, 2, 3], (item, index) => index < 2) // [1, 2]
複製代碼

2.3 使用"redece"來判斷括號是否匹配

這也是個例子來講明 reduce 這個函數功能的強大。給你一串字符串,你想要知道這串字符串的括號是不是匹配的。

常規的作法是使用棧來匹配,可是這裏咱們使用 reduce 就能夠作到,咱們只須要一個變量 counter ,這個變量的初始值是 0 , 當遇到 ( 的時候,counter ++ 當遇到 ) 的時候, counter -- 。 若是括號是匹配的,那麼這個 counter 最終的值是0

//Returns 0 if balanced.
const isParensBalanced = (str) => {
  return str.split('').reduce((counter, char) => {
    if(counter < 0) { //matched ")" before "("
      return counter;
    } else if(char === '(') {
      return ++counter;
    } else if(char === ')') {
      return --counter;
    }  else { //matched some other char
      return counter;
    }
    
  }, 0); //<-- starting value of the counter
}
isParensBalanced('(())') // 0 <-- balanced
isParensBalanced('(asdfds)') //0 <-- balanced
isParensBalanced('(()') // 1 <-- not balanced
isParensBalanced(')(') // -1 <-- not balanced
複製代碼

2.4 計算數組中元素出現的次數(將數組轉爲對象)

若是你想計算數組中元素出現的次數或者想把數組轉爲對象,那麼你可使用 reduce 來作到。

var cars = ['BMW','Benz', 'Benz', 'Tesla', 'BMW', 'Toyota'];
var carsObj = cars.reduce(function (obj, name) { 
   obj[name] = obj[name] ? ++obj[name] : 1;
  return obj;
}, {});
carsObj; // => { BMW: 2, Benz: 2, Tesla: 1, Toyota: 1 }
複製代碼

做者建議前往MDN學習,查看更多例子MDN

// 我也去看了一眼MDN,發現reduce真是個黑科技,promise串行這個應用很是秒啊。

3.對象解構

3.1 移除不想要的屬性

有時候你想要移除對象中的一些不須要的屬性,這個對象多是包含了某些敏感的信息或者只是由於這個對象太大了。咱們可使用解構來代替去遍歷這些屬性。

let {_internal, tooBig, ...cleanObject} = {el1: '1', _internal:"secret", tooBig:{}, el2: '2', el3: '3'};
console.log(cleanObject); // {el1: '1', el2: '2', el3: '3'}
複製代碼

在這個例子中,咱們想要移除 _internaltooBig 這兩個屬性,咱們能夠將他們分配給變量 _internaltooBig 中,剩下的屬性存放在 cleanObject 中,這就是咱們想要的。

3.2 在函數參數中使用嵌套對象解構

var car = {
  model: 'bmw 2018',
  engine: {
    v6: true,
    turbo: true,
    vin: 12345
  }
}
const modelAndVIN = ({model, engine: {vin}}) => {
  console.log(`model: ${model} vin: ${vin}`);
}
modelAndVIN(car); // => model: bmw 2018 vin: 12345
複製代碼

在這個例子中 engine 是一個嵌套在 car 裏面的對象,若是咱們只須要 engine 裏面的屬性 vin 咱們能夠這樣作。

3.3 合併對象

ES6 新增了一個擴展運算符,... 使用三個點來表示,它常常用來解構數組的值, 可是它也能夠用在對象中。

在這個例子中,咱們在一個新的對象中使用擴展運算符,後面一個對象的屬性值會把前面一個對象的屬性值覆蓋。

第二個對象中的屬性 bc 的值把第一個對象中屬性 bc 的值覆蓋掉了

let object1 = { a:1, b:2,c:3 }
let object2 = { b:30, c:40, d:50}
let merged = {…object1, …object2} //spread and re-add into merged
console.log(merged) // {a:1, b:30, c:40, d:50}
複製代碼

4.Sets

4.1 使用set來對數組去重

在ES6能夠很方便的使用Set來對數組去重,由於Set表示的是一個集合,一個元素會在集合裏面出現過一次。

let arr = [1, 1, 2, 2, 3, 3];
let deduped = [...new Set(arr)] // [1, 2, 3]
複製代碼
4.2 使用Array的方法

能夠經過(...)擴展運算符將 Set 轉換成 Array 這樣咱們就能夠在 Set 使用全部 Array 的方法了。

這個例子展現瞭如何在 Set 中使用 filter 方法

let mySet = new Set([1,2, 3, 4, 5]);
var filtered = [...mySet].filter((x) => x > 3) // [4, 5]
複製代碼

5.數組的解構

5.1 交換2個值

let param1 = 1;
let param2 = 2;
//swap and assign param1 & param2 each others values
[param1, param2] = [param2, param1];
console.log(param1) // 2
console.log(param2) // 1
複製代碼

5.2 函數返回多個值

async function getFullPost(){
  return await Promise.all([
    fetch('/post'),
    fetch('/comments')
  ]);
}
// const [post, comments] = getFullPost();
const [post, comments] = await getFullPost();
// 註釋掉的那一行是做者寫的,可是我跑不通,我以爲getFullPost是個Promise,因此須要加await。
複製代碼

咱們使用 async\await 來獲取2個接口的數據 /post/comments , 函數返回的是一個數組,因此可使用解構來得到這兩個接口的返回值。

做者原文章的內容就到這裏,可是我想補充一下map。

6. Map

在對象中的 key 只能是 string 沒辦法接受一個 Object 看成 key 會被自動轉換成字符串,例子以下:

const data = {};
const element = document.getElementById('myDiv');

data[element] = 'metadata';
data['[object HTMLDivElement]'] // "metadata"
複製代碼

因此對於鍵值對的數據解構,mapObject 更加合適。

6.1 在map中使用對象看成key

const M = new Map()
let o = {p: 'Hello World'}
M.set(o, 'hello world')
M.get(o) // hello world
let O = {p: 'Hello World'}
M.get(O) // undefined
複製代碼

注意: O != o 因此這個 M.get(O)undefined

6.2 WeakMap的做用

在普通的map中,若是一個 object 被看成 key 引用了,當除了map之外,其餘的變量都丟掉對這個 object 的引用,那map仍是會阻止垃圾回收機制去回收這個 object 這就會致使內存泄漏。因此就有了WeakMap。

字面意思,WeakMap裏面的key是弱引用,而且 WeakMap中只能以 Object 看成 key 由於其餘的你均可以用 Map搞啊~~那麼 WeakMap的幾個小技巧。

6.2.1 使用DOM節點做爲鍵名
let myElement = document.getElementById('logo');
let myWeakmap = new WeakMap();

myWeakmap.set(myElement, {timesClicked: 0});

myElement.addEventListener('click', function() {
  let logoData = myWeakmap.get(myElement);
  logoData.timesClicked++;
}, false);
複製代碼

以上例子來自 Ruanyifeng

咱們用WeakMap來存DOM節點的某些狀態,當這個DOM節點被刪除時,myElement失去了引用,全世界都失去了引用,WeakMap裏面所存的狀態就會消失,因此不會存在內存泄漏的問題。

6.2.2 使用WeakMap來部署私有屬性

咱們都知道,在JS中實現實例的私有屬性是比較困難的,有個辦法是使用閉包,可是閉包有個問題,實例被強引用,不能被垃圾回收機制處理。以下代碼:

var Person = (function() {
    var privateData = {},
        privateId = 0;
    function Person(name) {
        Object.defineProperty(this, "_id", { value: privateId++ });
        privateData[this._id] = {
            name: name
        };
    }
    Person.prototype.getName = function() {
        return privateData[this._id].name;
    };
    return Person;
}());
複製代碼

privateData對每一個實例都是強引用,因此垃圾回收機制是處理不了的。

咱們能夠用weakMap很好的解決這個問題。

var privateData = new WeakMap();
var Person = (function() {
    function Person(name) {
        privateData.set(this, { name: name });
    }
    Person.prototype.getName = function() {
        return privateData.get(this).name;
    };
    return Person;
}());
複製代碼

以上代碼weakMap不會對實例形成強引用,也就是說,垃圾回收機制是可能把這個實例回收掉的,若是沒有其餘人對這個實例保持着引用,是會被回收的,也就不會致使內存泄露了。

以上例子來自JavaScript實現私有屬性

相關文章
相關標籤/搜索