瞭解一下ES6: 函式&簡述深淺拷貝

王聖鬆發表於2018-10-15

標準開頭

瞭解一下ES6: 函式&簡述深淺拷貝

今天我們來看一下ES6的函式部分知識


函式

函式初始值

有時候,函式的非必填引數,我們可以給予其預設值。保證程式完整不會出錯

在早期,我們賦初始值可能是這樣做的:

// 早期ES5方法
function ajax(url, method, param) {
    method = method ? method : 'GET';
    param = param ? param : {};
    console.log(url, method, param);
}複製程式碼

但是這種方法不夠整潔和美觀。且維護較為麻煩

在ES6中,我們可以直接在引數欄上指定預設值

function ajax(url, method = 'GET', param = {}) {
    console.log(url, method, param)
}複製程式碼

這樣讓方法看起來更加整潔。且保證了程式的正常執行

我們可以用babel編譯為ES5程式碼review一下:

'use strict';

function ajax(url) {
    var method = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'GET';
    var param = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};

    console.log(url, method, param);
}

ajax('http://www.baidu.com');複製程式碼

轉換為ES5程式碼後,我們可以看出:其轉換方法就是判斷引數列表內是否有值且長度是否足夠。然後再進行判斷


函式剩餘操作符

在對於很多重複引數的函式,我們可以用“...”剩餘操作符進行省略

例如,我們現在有個方法,要把每個引數進行相加,引數可以隨便定義長度。但是長度必須>2

在ES5中,我們可能要重複寫好多的引數名。不僅造成浪費,也讓程式易讀性變差

function sum(param1, param2, param3, param4, param5) {
    console.log(param1 + param2 + param3 + param4 + param5);
}複製程式碼

其實我們從param2 - param5可以藉助ES6合併為同一個引數。且無需手動擴充套件

function sum(param1, ...paramN) {
    let result = param1;
    paramN.forEach((param) => {
        result += param
    });
    console.log(result);
}複製程式碼

合併後的引數會輸出為一個陣列,大家可以按照陣列的操作來操作它


函式引數解構

如果我們按照一個物件的方式當作引數傳入一個函式,且函式引數也是物件的方式接受。那我們可以完成一次解構

還記得之前解構要怎麼做嗎?要保證解構雙方的型別,資料格式要類似

function f({name, age}) {
    console.log(name, age);
}

f({name: 'janlay', age: 8});複製程式碼

不難理解


箭頭函式

箭頭函式應該是ES6函式中最Nice的一個知識了。中文名叫“箭頭函式”,英文名叫“Lambda表示式”。

箭頭函式是為了在你宣告方法時,更加簡單便捷。其語法如下:

 let sum = (a, b) => {
     return a + b;
 };複製程式碼

箭頭左邊的是引數列表,右邊的就是函式方法體

當你的函式只有一個引數時,你可以更加簡化函式方法

let result = num => num * 2;複製程式碼

但是當你使用箭頭函式時,你可就小心咯。我們用箭頭函式會涉及到一個叫“作用域”的問題。這個問題通常影響我們的關鍵字this的值


因為箭頭函式內呼叫this,作用域並不是指向箭頭函式本身,而是指向比箭頭函式還要大一層的函式。舉個栗子

let myInfo = {
    name: 'janlay',
    sayHello: () => {
        console.log(`Hi,My name is ${this.name}`)
    }
};

myInfo.sayHello();複製程式碼

這時候控制檯輸出undefined

正如我們所說的,箭頭函式內的this會指向它上一層函式中的作用域。但是他並沒有上一層函式體。所以我們列印this,也是顯示undefined



簡述深淺拷貝

先上這樣一段程式碼

let myInfo = {
    name: 'janlay',
    age: 17
};
let heInfo = {};
heInfo = myInfo;
heInfo.name = 'Mike';
console.log(myInfo);複製程式碼

按照一般邏輯,我們複製一份myInfo到heInfo。然後我們修改heInfo內的屬性,輸出myInfo應該不會變才對

但是我們錯了

{ name: 'Mike', age: 17 }複製程式碼

像這種物件拷貝叫做 “淺拷貝”。意味著只是拷貝了記憶體地址,但是並沒有再記憶體中複製一份給新變數

像這樣的淺拷貝,還有ES6的“Object.assign()”方法。他的作用是傳入2個物件進行合併,然後賦值給第三個物件。

有時候我們會用到淺拷貝,但是一般情況下我們要用到深拷貝。也就是我們常說的值傳遞


深拷貝的方式很多。由於本人學識有限,給大家帶來一個容易理解的深拷貝方法

1. JSON.parse()和JSON.stringify方法

這應該算是最簡單的深拷貝方法了。其原理就是將源物件轉化為一個JSON物件,然後用parse方法再釋放為一個物件。經過這麼一折騰,記憶體地址就發生了改變。也就達到了深拷貝的效果

let myInfo = {
    name: 'janlay',
    age: 17
};
let heInfo = {};
heInfo = JSON.parse(JSON.stringify(myInfo));
heInfo.name = 'Mike';
console.log(myInfo);複製程式碼

結果輸出為: { name: 'janlay', age: 17 }


2. 使用外接clone方法

其原理也很簡單,通過遍歷物件,讓物件的每個值都挨個複製給新物件,不再進行整體複製。細分到物件的最小單位

function clone(origin) {
    let newObj = {}; //新物件
    for (let key in origin) { //迴圈原始物件
        if (typeof origin[key] === 'object') { //如果物件內的屬性是一個物件
            newObj[key] = clone(origin[key]) // 用遞迴方式對物件內的物件進行拆分
        } else { //否則
            newObj[key] = origin[key]; //如果是簡單的屬性,直接複製
        }
    }
    return newObj; //返回拷貝後的新物件
}複製程式碼

呼叫  heInfo = clone(myInfo);

結果輸出為 { name: 'janlay', age: 17 }


以上兩種深拷貝方法都非常簡單。像瞭解更深度的深拷貝,這裡推薦一個掘金的另一篇文章

 深拷貝的終極探索(90%的人都不知道)


The End

Babel中文網 - ES6線上轉換ES5工具


相關文章