成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

ES6系列---函數(shù)

AJie / 893人閱讀

摘要:形參默認值不再影響對象當(dāng)使用默認參數(shù)值時,對象的行為與以往有所不同。具有方法的函數(shù)被統(tǒng)稱為構(gòu)造函數(shù)。當(dāng)調(diào)用函數(shù)的方法時,被賦值為新創(chuàng)建對象實例如果調(diào)用方法,則的值為。

由于JavaScript開發(fā)者多年的不斷抱怨和呼吁,ES6終于大力度地更新了函數(shù)特性,在ES5基礎(chǔ)上進行了許多改進。

函數(shù)形參的默認值 ES5形參默認值的實現(xiàn)

ES5中,你很可能通過以下這種方式為函數(shù)賦予默認值:

function makeRequest(url, timeout, callback) {
    timeout = timeout || 2000;
    callback = callback || function() {};
    
    // 函數(shù)的其余部分
}

對于函數(shù)的命名參數(shù),如果不顯式傳值,則其默認值為undefined。因此經(jīng)常是使用邏輯或操作符來為缺失的參數(shù)提供默認值。然而這個方式有缺陷,如果給第二個形參timeout傳入值0,盡管這個值是合法的,也會被視為false值,對函數(shù)調(diào)用方來說,timeout非預(yù)期的被修改為2000。

更安全的選擇是通過typeof檢查參數(shù)類型,就像這樣:

function makeRequest(url, timeout, callback) {
    timeout = (typeof timeout !== "undefined") ? timeout : 2000;
    callback = (typeof callback !== "undefined") ? callback : function() {};
    
    // 函數(shù)的其余部分
}

在流行的JavaScript庫中均使用類似的模式進行默認值補全。

ES6形參默認值的實現(xiàn)

ES6簡化了為形參提供默認值的過程,定義形參時即可指定初始值:

function makeRequest(url, timeout = 2000, callback) {
    // 函數(shù)的其余部分
}

這種情況下,只有當(dāng)不為第二個參數(shù)傳值或主動為第二個參數(shù)傳入undefined時才會使用timeout的默認值,就像這樣:

// 使用timeout的默認值
makeRequest("/foo", undefined, function(body) {
    doSomething(body);
});

// 使用timeout的默認值
makeRequest("/foo");

// 不使用timeout的默認值
makeRequest("foo", null, function(body){ // null是一個合法值
    doSomething(body);
});
ES6默認參數(shù)表達式

ES6中,關(guān)于默認參數(shù)值,還可以是非原始值傳參,就像這樣:

function getValue() {
    return 5;
}

function add(first, second = getValue()) {
    return first + second;
}

console.log(add(1, 1));  // 2
console.log(add(1));     // 6

尤其注意,初次解析函數(shù)聲明時是不會調(diào)用getValue()方法的,只有當(dāng)調(diào)用add()函數(shù)且不傳入第二個參數(shù)時才會被調(diào)用。另外,second = getValue()這里的小括號()不要忘記掉,不然最終傳入的是對函數(shù)的引用,而不是函數(shù)調(diào)用的結(jié)果。

正因為默認參數(shù)是在函數(shù)調(diào)用時求值,所以可以使用先定義的參數(shù)作為后定義的參數(shù)的默認值,就像這樣:

function add(first, second = first) {
    return first + second;
}

console.log(add(1, 1));   // 2
console.log(add(1));      // 2

也可以將參數(shù)first傳入一個函數(shù)來獲得參數(shù)second的值,就像這樣:

function getValue(value) {
    return value + 5;
}

function add(first, second = getValue(first)) {
    return first + second;
}

console.log(add(1, 1));  // 2
console.log(add(1));     // 7
默認參數(shù)的臨時死區(qū)

在引用參數(shù)默認值的時,只允許引用前面參數(shù)的值,即先定義的參數(shù)不能訪問后定義的參數(shù):

function add(first = second, second) {
    return first + second;
}

console.log(add(1, 1));   // 2
console.log(add(undefined, 1));   // 拋出錯誤

在講解letconst時介紹了臨時死區(qū)(TDZ),其實默認參數(shù)也有同樣的臨時死區(qū)。上面這個示例,調(diào)用add(1, 1)和add(undefined, 1)相當(dāng)于引擎在背后做了如下事情:

// 表示調(diào)用add(1, 1)時的JavaScript代碼
let first = 1;
let second = 1;

// 表示調(diào)用add(undefined, 1)時的JavaScript代碼
let first = second;
let second = 1;

這個示例中,調(diào)用add(undefined, 1)函數(shù),因為當(dāng)first初始化時second尚未初始化,所以會導(dǎo)致程序拋出錯誤,此時second(已聲明,未初始化)尚處于臨時死區(qū)中,正如討論let綁定時所說的那樣,任何引用臨時死區(qū)中的綁定的行為都會報錯。

函數(shù)參數(shù)有自己的作用域和臨時死區(qū),其與函數(shù)體的作用域是各自獨立的,也就是說參數(shù)的默認值不可訪問函數(shù)體內(nèi)聲明的變量。

ES6形參默認值不再影響arguments對象

當(dāng)使用默認參數(shù)值時,arguments對象的行為與以往有所不同。在ES5非嚴格模式下,函數(shù)命名參數(shù)的變化會體現(xiàn)在arguments對象中:

function mixArgs(first, second) {
    console.log(first === arguments[0]);
    console.log(second === arguments[1]);
    first = "c";
    second = "d";
    console.log(first === arguments[0]);
    consolo.log(second === arguments[1]);
}

mixArgs("a", "b");

這段代碼會輸出:

true
true
true
true

ES5非嚴格模式下,命名參數(shù)的變化會同步更新到arguments對象中,所以當(dāng)firstsecond被賦予新值時,arguments[0]和arguments[1]相應(yīng)地也就更新了,最終所有===全等結(jié)果都為true

ES5嚴格模式下,取消了arguments對象的這個令人感到困惑的行為,無論參數(shù)如何變化,arguments對象不再隨之改變。ES6中,arguments對象的行為與ES5嚴格模式下保持一致。arguments對象保持與命名參數(shù)分離,這個微妙的細節(jié)將影響你使用arguments對象的方式,請看以下代碼:

function mixArgs(first, second = "b") {
    console.log(arguments.length);
    console.log(first === arguments[0]);
    console.log(second === arguments[1]);
    first = "c";
    second = "d";
    console.log(first === arguments[0]);
    console.log(second === arguments[1]);
}

mixArgs("a");

這段代碼會輸出以下內(nèi)容:

1
true
false
false
false
false

改變firstsecond并不會影響arguments對象??偸强梢酝ㄟ^arguments對象將參數(shù)恢復(fù)為初始值。

處理無命名參數(shù)

JavaScript的函數(shù)語法規(guī)定,無論函數(shù)已定義的命名參數(shù)有多少,都不限制調(diào)用時傳入的實際參數(shù)數(shù)量。當(dāng)傳入更少數(shù)量的參數(shù)時,默認參數(shù)值的特性可以有效簡化函數(shù)的聲明;當(dāng)傳入更多數(shù)量的參數(shù)時,ES6同樣也提供了更好的方案。

ES5中的無命名參數(shù)

早先,我們用JavaScript提供的arguments對象來檢查函數(shù)的所有參數(shù),從而不必定義每一個要用的參數(shù),看下面的例子:

function pick(object) {
    let result = Object.create(null);
    
    // 從第二個參數(shù)開始
    for(let i = 1, len = arguments.length; i < len; i++) {
        result[arguments[i]] = object[arguments[i]];
    }
    
    return result;
}

let book = {
    title: "ECMAScript 6",
    author: "Nicholas",
    year: 2016
};

let bookData = pick(book, "author", "year");

console.log(bookData.author);   // "Nicholas"
console.log(bookData.year);     // 2016

這個函數(shù)模仿了Underscore.js庫中的pick()方法,返回一個給定對象的副本,包含原始對象屬性的特定子集。在這個示例中只定義了一個參數(shù),第一個參數(shù)傳入的是被復(fù)制的源對象,其他參數(shù)為被復(fù)制屬性的名稱。

關(guān)于pick()函數(shù)應(yīng)該注意這樣幾件事:首先,并不容易發(fā)現(xiàn)這個函數(shù)可以接受任意數(shù)量的參數(shù),當(dāng)然,可以定義更多的參數(shù),但是怎么也達不到要求;其次,因為第一個參數(shù)為命名參數(shù)并已被使用,當(dāng)你要查找需要拷貝的屬性名稱時,不得不從索引1而不是索引0開始遍歷arguments對象。牢記真正的索引位置并不難,但這總歸是我們需要牽掛的問題。

ES6中,通過引入不定參數(shù)(rest parameters)的特性可以輕易解決這些問題。

ES6的不定參數(shù)

在函數(shù)的命名參數(shù)前添加三個點(...)就表明這是一個不定參數(shù),該參數(shù)為一個數(shù)組,包含著自它之后傳入的所有參數(shù)。使用不定參數(shù)重寫pick()函數(shù):

function pick(object, ...keys) {
    let result = Object.create(null);
    
    for(let i = 0, len = keys.length; i < len; i++) {
        result[keys[i]] = object[keys[i]];
    }
    
    return result;
}

只需要看一眼就知曉該函數(shù)可以處理的參數(shù)數(shù)量。
注意一下,函數(shù)的length屬性統(tǒng)計的是函數(shù)命名參數(shù)的數(shù)量,不定參數(shù)的加入不會影響函數(shù)length屬性。在本示例中pick()函數(shù)的length值為1,因為只會計算object。另外每個函數(shù)最多只能聲明一個不定參數(shù),并且一定要放在末尾。

不定參數(shù)對arguments對象的影響

不定參數(shù)的設(shè)計初衷是代替JavaScriptarguments對象的。但是arguments對象依然存在。如果聲明函數(shù)時定義了不定參數(shù),則在函數(shù)被調(diào)用時,arguments對象包含了所有傳入函數(shù)的參數(shù),就像這樣:

function checkArgs(...args) {
    console.log(args.length);
    console.log(arguments.length);
    console.log(args[0], arguments[0]);
    console.log(args[1], arguments[1]);
}

checkArgs("a", "b");

調(diào)用checkArgs(),輸出以下內(nèi)容:

2
2
a a
b b

無論是否使用不定參數(shù),arguments對象總是包含所有傳入函數(shù)的參數(shù)。

展開運算符配合不定參數(shù)

展開運算符可以讓你指定一個數(shù)組,將它們打散后作為各自獨立的參數(shù)傳入函數(shù)。正好,不定參數(shù)希望的就是指定多個各自獨立的參數(shù),并通過整合后的數(shù)組來訪問:

function max(...args) {
    // 計算并返回最大值
}

let values = [10, 20, 30, 40];
// 使用展開運算符打散
max(...values);
// 等價于
// max(10, 20, 30, 40)
構(gòu)造函數(shù)

ES5及早期版本中的函數(shù)具有多重功能,可以結(jié)合new使用,函數(shù)內(nèi)的this值將指向一個新對象,函數(shù)最終會返回這個新對象:

function Person(name) {
    this.name = name;
}

var person = new Person("Nicholas");
var notAPerson = Person("Nicholas");

console.log(person);      // "[Object Object]"
console.log(notAPerson);  // "undefined"

JavaScript函數(shù)有兩個不同的內(nèi)部方法:[[Call]]和[[Construct]]。當(dāng)通過new關(guān)鍵字調(diào)用函數(shù)時,執(zhí)行的是[[Construct]]函數(shù),它負責(zé)創(chuàng)建一個通常被稱作實例的新對象,然后再執(zhí)行函數(shù)體,將this綁定到實例上,并返回這個對象;如果不通過new關(guān)鍵字調(diào)用函數(shù),則執(zhí)行[[Call]]函數(shù),從而直接執(zhí)行代碼中的函數(shù)體。具有[[Construct]]方法的函數(shù)被統(tǒng)稱為構(gòu)造函數(shù)。

不是所有函數(shù)都有[[Construct]]方法,因此不是所有函數(shù)都可以通過new來調(diào)用,比如ES6的箭頭函數(shù)就沒有這個[[Construct]]。

ES5判斷函數(shù)是否用new調(diào)用

ES5中,如果想判斷一個函數(shù)是否通過new關(guān)鍵字被調(diào)用,最流行的方式是使用instanceof

function Person(name) {
    if(this instanceof Person) {
        this.name = name;  // 如果通過new關(guān)鍵字調(diào)用
    } else {
        throw new Error("必須通過new關(guān)鍵字來調(diào)用Person。");
    }
}

var person = new Person("Nicholas");
var notAPerson = Person("Nicholas");  // 拋出錯誤

但是這個方法也不完全可靠,因為有一種不通過new關(guān)鍵字的方法也可以將this綁定到Person的實例上:

function Person(name) {
    if(this instanceof Person) {
        this.name = name;
    } else {
        throw new Error("必須通過new關(guān)鍵字來調(diào)用Person。");
    }
}

var person = new Person("Nicholas");
var notAPerson = Person.call(person, "Michael");  // 有效!

調(diào)用Person.call()時將變量person傳入作為第一個參數(shù),相當(dāng)于在Person函數(shù)里將this設(shè)為了person實例。對于函數(shù)本身,無法區(qū)分是通過Person.call()(或者是Person.apply())還是new關(guān)鍵字調(diào)用得到的Person的實例。

ES6判斷函數(shù)是否用new調(diào)用

為了解決判斷函數(shù)是否通過new關(guān)鍵字調(diào)用的問題,ES6引入了new.target這個元屬性。當(dāng)調(diào)用函數(shù)的[[Construct]]方法時,new.target被賦值為新創(chuàng)建對象實例;如果調(diào)用[[Call]]方法,則new.target的值為undefined。

可以通過檢查new.target是否被定義過來安全的檢測一個函數(shù)是否是通過new關(guān)鍵字調(diào)用的,就像這樣:

function Person(name) {
    // typeof new.target === Person 可以檢查是否被某個特定的構(gòu)造函所調(diào)用
    if(typeof new.target !== "undefined") {
        this.name = name;
    } else {
        throw new Error("必須通過new關(guān)鍵字來調(diào)用Person。");
    }
}

var person = new Person("Nicholas");
var notAPerson = Person.call(person, "Michael");  // 拋出錯誤!
箭頭函數(shù)

ES6中,箭頭函數(shù)是最有趣的新增特性。它與傳統(tǒng)的JavaScript函數(shù)有些許不同,主要集中在以下方面:

沒有this、super、arguments和new.target綁定
箭頭函數(shù)中的this、super、arguments及new.target這些值由外圍最近一層非箭頭函數(shù)決定。

不能通過new關(guān)鍵字調(diào)用
箭頭函數(shù)沒有[[Construct]]方法,所以不能被用作構(gòu)造函數(shù),如果通過new關(guān)鍵字調(diào)用箭頭函數(shù),程序會拋出錯誤。

沒有原型
由于不可以通過new關(guān)鍵字調(diào)用箭頭函數(shù),因而沒有構(gòu)建原型的需求,所以箭頭函數(shù)不存在prototype這個屬性。

不可以改變this的綁定
函數(shù)內(nèi)部的this值不可被改變,在函數(shù)的生命周期內(nèi)始終保持一致。

不支持arguments對象
箭頭函數(shù)沒有arguments綁定,所以你必須通過命名參數(shù)和不定參數(shù)這兩種形式訪問函數(shù)的參數(shù)。

不支持重復(fù)的命名參數(shù)
箭頭函數(shù)不支持重復(fù)的命名參數(shù);而在傳統(tǒng)函數(shù)的規(guī)定中,只有在嚴格模式下才不能有重復(fù)的命名參數(shù)。

this綁定是JavaScript程序中常見的錯誤來源,在函數(shù)內(nèi)很容易就對this的值失去控制,其經(jīng)常導(dǎo)致程序出現(xiàn)意想不到的行為,箭頭函數(shù)消除了這方面的煩惱。

箭頭函數(shù)的語法

單一參數(shù):

let reflect = value => value;

// 相當(dāng)于
let reflect = function(value) {
    return value;
};

兩個以上參數(shù):

let sum = (num1, num2) => num1 + num2;

// 相當(dāng)于
let sum = function(num1, num2) {
    return num1 + num2;
};

沒有參數(shù):

let getName = () => "Nicholas";

// 相當(dāng)于
let getName = function(){
    return "Nicholas";
};

多表達式組成的更傳統(tǒng)的函數(shù)體:

let sum = (num1, num2) => {
    return num1 + num2;
};

// 相當(dāng)于
let sum = function(num1, num2) {
    return num1 + num2;
};

空函數(shù):

let doNothing = () => {};

// 相當(dāng)于
let doNothing = function(){};

返回對象字面量:

let getTempItem = id => ({ id: id, name: "Temp" });

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

將對象字面量包裹在小括號中是為了將其與函數(shù)體區(qū)分開來。

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/84960.html

相關(guān)文章

  • ES6 系列之 Babel 是如何編譯 Class 的(上)

    摘要:前言在了解是如何編譯前,我們先看看的和的構(gòu)造函數(shù)是如何對應(yīng)的。這是它跟普通構(gòu)造函數(shù)的一個主要區(qū)別,后者不用也可以執(zhí)行。該函數(shù)的作用就是將函數(shù)數(shù)組中的方法添加到構(gòu)造函數(shù)或者構(gòu)造函數(shù)的原型中,最后返回這個構(gòu)造函數(shù)。 前言 在了解 Babel 是如何編譯 class 前,我們先看看 ES6 的 class 和 ES5 的構(gòu)造函數(shù)是如何對應(yīng)的。畢竟,ES6 的 class 可以看作一個語法糖,...

    shadajin 評論0 收藏0
  • 使用JavaScript ES6的新特性計算Fibonacci(非波拉契數(shù)列)

    摘要:采用的生成非波拉契數(shù)列提供了原生的支持,語法非常有特色,關(guān)鍵字后面緊跟一個星號。的詳細介紹參考官網(wǎng)先看如何用這個黑科技重新實現(xiàn)非波拉契樹立的生成。在這個內(nèi)部,我們定義了一個無限循環(huán),用于計算非波拉契數(shù)列。 程序員面試系列 Java面試系列-webapp文件夾和WebContent文件夾的區(qū)別? 程序員面試系列:Spring MVC能響應(yīng)HTTP請求的原因? Java程序員面試系列-什么...

    yanbingyun1990 評論0 收藏0
  • ES6 系列之箭頭函數(shù)

    摘要:回顧我們先來回顧下箭頭函數(shù)的基本語法。主要區(qū)別包括沒有箭頭函數(shù)沒有,所以需要通過查找作用域鏈來確定的值。箭頭函數(shù)并沒有方法,不能被用作構(gòu)造函數(shù),如果通過的方式調(diào)用,會報錯。 回顧 我們先來回顧下箭頭函數(shù)的基本語法。 ES6 增加了箭頭函數(shù): let func = value => value; 相當(dāng)于: let func = function (value) { return ...

    hsluoyz 評論0 收藏0
  • webpack4 系列教程(二): 編譯 ES6

    摘要:今天介紹怎么編譯的各種函數(shù)和語法。對于相關(guān)的匹配規(guī)則,除了匹配結(jié)尾的文件,還應(yīng)該去除文件夾下的第三庫的文件發(fā)布前已經(jīng)被處理好了。它需要在我們項目的入口文件中被引入,或者在中配置。個人網(wǎng)站原文鏈接系列教程二編譯 今天介紹webpack怎么編譯ES6的各種函數(shù)和語法。敲黑板:這是webpack4版本哦, 有一些不同于webpack3的地方。 >>> 本節(jié)課源碼 >>> 所有課程源碼 1....

    graf 評論0 收藏0
  • ES6 系列之 Babel 是如何編譯 Class 的(下)

    摘要:以上的代碼對應(yīng)到就是調(diào)用父類的值得注意的是關(guān)鍵字表示父類的構(gòu)造函數(shù),相當(dāng)于的。舉個例子這是因為作為構(gòu)造函數(shù)的語法糖,同時有屬性和屬性,因此同時存在兩條繼承鏈。子類的屬性,表示構(gòu)造函數(shù)的繼承,總是指向父類。 前言 在上一篇 《 ES6 系列 Babel 是如何編譯 Class 的(上)》,我們知道了 Babel 是如何編譯 Class 的,這篇我們學(xué)習(xí) Babel 是如何用 ES5 實現(xiàn)...

    endiat 評論0 收藏0
  • ES6系列函數(shù)部分

    摘要:正是因為它沒有,所以也就不能用作構(gòu)造函數(shù)。不可以當(dāng)作構(gòu)造函數(shù),也就是說,不可以使用命令,否則會拋出一個錯誤。不可以使用對象,該對象在函數(shù)體內(nèi)不存在。 箭頭函數(shù) 在之前ES5的版本中,我們定義一個函數(shù)的形式如下: function a() { // do something…… } 但是在ES6中,則新增了箭頭函數(shù)的方式,ES6中允許使用箭頭(=>)來定義函數(shù)。 () => { ...

    enda 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<