第3章 函數(shù)改動

ES6 functions改動

ES6函數(shù)的改變不算太大祠丝,都是一些其他語言早就有的功能钾军,而Javascript一直比較欠缺的窒舟,比如函數(shù)參數(shù)默認(rèn)值,任意參數(shù)的表示法淌哟,最大的變化應(yīng)該是支持箭頭函數(shù)(其他語言稱之為LAMBDA表達(dá)式)迹卢,一種對匿名函數(shù)的一種簡寫方式,以下來探討一下函數(shù)在ES6中的一些改變:

1. 默認(rèn)參數(shù)(default parameters)
2. 任意參數(shù)(rest parameters ...)
3. spread 操作符(...)
4. new.target 元屬性
5. 箭頭函數(shù)( => )
6. 其他一些改動(miscellaneous)


1.默認(rèn)參數(shù)

ES6之前一直是通過其他方法來模擬默認(rèn)參數(shù)的徒仓,例如邏輯或||符號腐碱,ES6版本真正意義上支持這種便利的寫法。

// ES5模擬默認(rèn)參數(shù)
function person(name, age) {
    name = name || "James";
    age = age || "18";
    console.log(name + " " + age);
}
// 一般情況下這種寫法是沒問題的,當(dāng)邏輯或前面的值為falsy值喂走,整個表達(dá)式返回后面的值
// 例如:
  person("Louis"); // ok
person(); // ok
person(undefined, 20); // ok
person("baby", 0); // "baby 18" error, 0為falsy值

上面可以看出這種寫法是有一定問題的,各種JS庫給出了另一種寫法

function person(name, age) {
    if (typeof name === "undefined") {
        name = name || "James"; 
    }
    if (typeof age === "undefined") {
        age = age || "18";
    }
    console.log(name + " " + age);
}
person(undefined, 0); // ok "James 0"

ES6寫法

function person(name = "James", age = 18) {
    console.log(name + " " + age);
}

// 1各種寫法 默認(rèn)參數(shù)出現(xiàn)在中間
function getRequest(url, timeout = 2000, callback) {
    // do something
}
gerRequest("/foo", undefined, function() {

});

// 2默認(rèn)參數(shù)表達(dá)式
let value = 5;
function getValue() {
    return value++;
}
function add(first, second = getValue()) {
    return first + second;
}
add(3); // 8
add(3); // 9
add(1, 1); // 2

// 3后面參數(shù)引用前面參數(shù)
function add(first, second = first) {
    return first + second;
}
add(2); // 4
add(3, 4); // 7

默認(rèn)參數(shù)<b>TDZ(暫時死區(qū))</b>情況:

// 上面的第三種寫法谋作,若寫成第一個參數(shù)引用第二個參數(shù)
function add(first = second, second) {
    return first + second;
}
add(1, 1); // ok 2
add(undefined, 4); // THROW AN ERROR 第二個參數(shù)未聲明就引用就會拋出錯誤
// 就相當(dāng)于
let first = second; // error
let second = 4;

2.任意參數(shù)

ES6任意參數(shù)用"...."表示,任意參數(shù)和arguments之間的差別
ES5使用arguments參數(shù)來實(shí)現(xiàn)對象屬性拷貝:

function pick(object) {
    var result = Object.create(null); // 創(chuàng)建一個對象
    for (var i = 0, len = arguments.length - 1; i < len; i++) {
        result[arguments[i]] = object[arguments[i]];
    }
    return result;
}
// arguments將object也計(jì)入吭净,所以除開第一個參數(shù)要減1
var book = {
    title: "understanding ES6",
    author: "Nicholas C.Zakes",
    year: 2016
};
var o = pick(book, "author", "year");
o.author; // "Nicholas C.Zakes"
o.year; // 2016

上面的pick函數(shù)看上去不夠直觀,因?yàn)槌谝粋€參數(shù)外不知道要添加幾個參數(shù)友扰,使用新語法

function pick(object, ...keys) {
    var result = Object.create(null); // 創(chuàng)建一個對象
    for (var i = 0, len = keys.length; i < len; i++) {
        result[keys[i]] = object[keys[i]];
    }
    return result;
}
// keys將object不計(jì)入在其內(nèi)
var book = {
    title: "understanding ES6",
    author: "Nicholas C.Zakes",
    year: 2016
};
var o = pick(book, "author", "year");
o.author; // "Nicholas C.Zakes"
o.year; // 2016

使用rest parameters注意事項(xiàng)

1.要將任意參數(shù)放到函數(shù)的最后澳泵,不能放在中間位置

2.不能用于對象字面量setter中

function pick(object, ...keys, last) { //... }
// 語法錯誤

let object = {
    set name(...value) {
        // do something
    }
};
// 語法錯誤

3.spread操作符

spread操作符和rest parameters一樣碰辅,都使用 "..." 表示,spread操作符允許我們將數(shù)組中的參數(shù)一個一個傳入函數(shù)中
例如:

// Math.max()函數(shù), 一般可以加入任意個參數(shù)
Math.max(12, 13, 14, 15); // 15

// 以數(shù)組的形式
var arr = [1, 2, 3, 4];
Math.max.apply(null, arr); // 4

// 使用 "..."
Math.max(...arr); // 4
// 還可以加入其它的一些參數(shù)
Math.max(...arr, 5, 10); // 10

將一個數(shù)組去重:

var arr = [1, 2, 2, 4, 4];
// 使用Set將重復(fù)的去掉,然后將set對象轉(zhuǎn)變?yōu)閿?shù)組
var mySet = new Set(arr); // mySet {1, 2, 4}

// 方法1迁酸,使用Array.from轉(zhuǎn)變?yōu)閿?shù)組
// var arr = Array.from(mySet); // [1, 2, 4]

// 方法2闹蒜,使用spread操作符
var arr = [...arr]; // [1, 2, 4]

// 方法3, 傳統(tǒng)forEach
var arr2 = [];
mySet.forEach(v => arr2.push(v)); 

4.new.target元屬性

????函數(shù)內(nèi)部有兩個方法 [[call]][[construct]] (箭頭函數(shù)沒有這個方法)荣月,當(dāng)使用new 操作符時, 函數(shù)內(nèi)部調(diào)用 [[construct]], 創(chuàng)建一個新實(shí)例蹲蒲,this指向這個實(shí)例; 不使用new 操作符時宴胧, 函數(shù)內(nèi)部調(diào)用 [[call]]

????判斷一個函數(shù)是否使用new操作符,ES5的方法:

function Person(name) {
    if (this instanceof Person) {
        this.name = name;
    } else {
        throw new Error("You must use new operator");
    }
}
var p = new Person("James"); // ok
var p = Person("James"); // error
// 但是可以通過其他方式繞過這種錯誤
var notPerson = Person.call(p, "Nicholas"); // works

ES6 通過new.target 來判斷是否使用new,元屬性 是指一個提供目標(biāo)相關(guān)額外信息(比如new)的非對象屬性。

function Person(name) {
    if (typeof new.target !== "undefined") {
        this.name = name;
    } else {
        throw new Errow("You must use new operator");
    }
}
var p = new Person("James"); // ok
var notPerson = Person.call(p, "Louis"); // error 

5.箭頭函數(shù)

箭頭函數(shù)有以下幾個方面的特點(diǎn):

  1. this, super, arguments和arguments的值由最近一個包含它的非箭頭函數(shù)定義斧吐。(No this, superm arguments and new.target bindings);
  2. 箭頭函數(shù)內(nèi)部沒有 [[construct]]方法, 因此不能當(dāng)作構(gòu)造器郊闯,使用new操作符育拨;
  3. 不存在原型(No prototype);
  4. 不能改變this, 在整個箭頭函數(shù)生命周期this值保持不變;
  5. 不存在arguments對象怀挠,不過包含它的函數(shù)存在析蝴,箭頭函數(shù)依靠命名參數(shù)和rest parameters;
  6. 不能擁有重復(fù)的命名參數(shù)绿淋,ES5只有嚴(yán)格模式下才不允許

1.箭頭函數(shù)語法

// 語法很簡單
let sum = (n1, n2) => n1 + n2;
// 相當(dāng)于
let sum = function(n1, n2) {
    return n1 + n2;
};

let getTempItem = id => ({ id: id, name: "Temp" });
// 相當(dāng)于
let getTempItem = function(id) {
    return {
        id: id,
        name: "Temp"
    };
};

2.沒有this綁定

let PageHandler = {
    id: "123456",
    init: function() {
        document.addEventListener("click", function(event) {
            this.doSomething(event.type); // error
        }, false);
    },
    doSomething: function(type) {
        console.log("Handling " + type + " for " + this.id);
    }
};
// init函數(shù)中的this.doSomething闷畸,this指向的是函數(shù)內(nèi)部document對象,而不是PageHandler對象

使用箭頭函數(shù)改寫:

let PageHandler = {
    id: "123456",
    init: function() {
        document.addEventListener("click", event => this.doSomething(evnet.type)
        }, false);
    },
    doSomething: function(type) {
        console.log("Handling " + type + " for " + this.id);
    }
};
// 此處箭頭函數(shù)this指向包含它的函數(shù)躬它,即init,init為PageHandler的方法腾啥,
// this指向PageHandler對象實(shí)例

3.不能使用new

var MyType = () => {};
var obj = new MyType(); // Error

4.沒有arguments對象

箭頭函數(shù)沒有arguments對象,但是可以使用包含函數(shù)中的arguments對象

function createArrowFunctionReturningFirstArg() {
    // arguments 為 createArrowFunctionReturningFirstArg中的對象
    return  () => arguments[0]; 
}
var arrowFunction = createArrowFunctionReturningFirstArg(10);
arrFunction(); // 10

6.其他(misllanceous)

其他的一些變化:

  1. 添加name屬性用來判斷函數(shù)名冯吓,用于調(diào)試;
  2. 規(guī)范塊級別函數(shù)(block-level functions)倘待,當(dāng)執(zhí)行流結(jié)束塊級別函數(shù)退出,塊級別函數(shù)提升變量到塊頂部组贺;
  3. 對尾部調(diào)用(Tail call, 值一個函數(shù)返回另一個函數(shù)對象)性能進(jìn)行優(yōu)化凸舵,尤其是都遞歸函數(shù)性能提升很大

總結(jié)

  1. ES6對默認(rèn)參數(shù)的支持;
  2. 任意參數(shù)和spread操作符
  3. 箭頭函數(shù)

????總體來說,這些改動都是為編寫程序提供了極大的便利失尖,不用再使用workaround來解決語法存在的問題啊奄,整體來講,更加符合語言的書寫習(xí)慣掀潮。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末菇夸,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子仪吧,更是在濱河造成了極大的恐慌庄新,老刑警劉巖薯鼠,帶你破解...
    沈念sama閱讀 217,509評論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件羞芍,死亡現(xiàn)場離奇詭異,居然都是意外死亡郊艘,警方通過查閱死者的電腦和手機(jī)荷科,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,806評論 3 394
  • 文/潘曉璐 我一進(jìn)店門唯咬,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人畏浆,你說我怎么就攤上這事副渴。” “怎么了全度?”我有些...
    開封第一講書人閱讀 163,875評論 0 354
  • 文/不壞的土叔 我叫張陵煮剧,是天一觀的道長。 經(jīng)常有香客問我将鸵,道長勉盅,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,441評論 1 293
  • 正文 為了忘掉前任顶掉,我火速辦了婚禮草娜,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘痒筒。我一直安慰自己宰闰,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,488評論 6 392
  • 文/花漫 我一把揭開白布簿透。 她就那樣靜靜地躺著移袍,像睡著了一般。 火紅的嫁衣襯著肌膚如雪老充。 梳的紋絲不亂的頭發(fā)上葡盗,一...
    開封第一講書人閱讀 51,365評論 1 302
  • 那天,我揣著相機(jī)與錄音啡浊,去河邊找鬼觅够。 笑死,一個胖子當(dāng)著我的面吹牛巷嚣,可吹牛的內(nèi)容都是我干的喘先。 我是一名探鬼主播,決...
    沈念sama閱讀 40,190評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼廷粒,長吁一口氣:“原來是場噩夢啊……” “哼窘拯!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起评雌,我...
    開封第一講書人閱讀 39,062評論 0 276
  • 序言:老撾萬榮一對情侶失蹤树枫,失蹤者是張志新(化名)和其女友劉穎直焙,沒想到半個月后景东,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,500評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡奔誓,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,706評論 3 335
  • 正文 我和宋清朗相戀三年斤吐,在試婚紗的時候發(fā)現(xiàn)自己被綠了搔涝。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,834評論 1 347
  • 序言:一個原本活蹦亂跳的男人離奇死亡和措,死狀恐怖庄呈,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情派阱,我是刑警寧澤诬留,帶...
    沈念sama閱讀 35,559評論 5 345
  • 正文 年R本政府宣布,位于F島的核電站贫母,受9級特大地震影響文兑,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜腺劣,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,167評論 3 328
  • 文/蒙蒙 一绿贞、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧橘原,春花似錦籍铁、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,779評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至芋酌,卻和暖如春靡狞,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背隔嫡。 一陣腳步聲響...
    開封第一講書人閱讀 32,912評論 1 269
  • 我被黑心中介騙來泰國打工甸怕, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人腮恩。 一個月前我還...
    沈念sama閱讀 47,958評論 2 370
  • 正文 我出身青樓梢杭,卻偏偏與公主長得像,于是被迫代替她去往敵國和親秸滴。 傳聞我的和親對象是個殘疾皇子武契,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,779評論 2 354

推薦閱讀更多精彩內(nèi)容