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

資訊專欄INFORMATION COLUMN

深入理解ES6筆記(三)函數(shù)

aristark / 2012人閱讀

摘要:主要知識(shí)點(diǎn)有函數(shù)參數(shù)默認(rèn)值剩余參數(shù)擴(kuò)展運(yùn)算符屬性塊級(jí)函數(shù)箭頭函數(shù)以及尾調(diào)用優(yōu)化深入理解筆記目錄函數(shù)的默認(rèn)參數(shù)在中,我們給函數(shù)傳參數(shù),然后在函數(shù)體內(nèi)設(shè)置默認(rèn)值,如下面這種方式。擁有方法的函數(shù)被稱為構(gòu)造器。

主要知識(shí)點(diǎn)有:函數(shù)參數(shù)默認(rèn)值、剩余參數(shù)、擴(kuò)展運(yùn)算符、new.target屬性、塊級(jí)函數(shù)、箭頭函數(shù)以及尾調(diào)用優(yōu)化

《深入理解ES6》筆記 目錄

函數(shù)的默認(rèn)參數(shù)

在ES5中,我們給函數(shù)傳參數(shù),然后在函數(shù)體內(nèi)設(shè)置默認(rèn)值,如下面這種方式。

function a(num, callback) {
  num = num || 6
  callback = callback || function (data) {console.log("ES5: ", data)}
  callback(num * num)
}
a() //ES5: 36,不傳參輸出默認(rèn)值

//你還可以這樣使用callback
a(10, function(data) {
  console.log(data * 10) // 1000, 傳參輸出新數(shù)值
})

弊端:此處的 num 的有效值實(shí)際上有可能是 0 ,但因?yàn)? 0 是假值,就會(huì)導(dǎo)致 num 的值在這種情況下會(huì)被替換為 6;
可以用 typeof 來(lái)檢測(cè)參數(shù)的類型:

function a(num, callback) {
  num = (typeof num!== "undefined") ? num: 6;
  callback = (typeof callback !== "undefined") ? callback : function (data) {console.log("ES5: ", data)};
  callback(num * num)
}

雖然這種方法更安全,但依然為實(shí)現(xiàn)一個(gè)基本需求而書(shū)寫(xiě)了過(guò)多的代碼。它代表了一種公共
模式,而流行的 JS 庫(kù)中都充斥著類似的模式。

ES6 中的參數(shù)默認(rèn)值
function a(num = 6, callback = function (data) {console.log("ES6: ", data)}) {
  callback(num * num)
}

a() //ES6: 36, 不傳參輸出默認(rèn)值

a(10, function(data) {
  console.log(data * 10) // 1000,傳參輸出新數(shù)值
})

使用ES6的默認(rèn)值寫(xiě)法可以讓函數(shù)體內(nèi)部的代碼更加簡(jiǎn)潔優(yōu)雅

參數(shù)默認(rèn)值如何影響 arguments 對(duì)象

ES5 的非嚴(yán)格模式下

function mixArgs(first, second) {
    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", "b");
//輸出
true
true
true
true

ES5 的嚴(yán)格模式下

function mixArgs(first, second) {
    "use strict";
    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", "b");
//輸出
true
true
false
false

ES6

arguments 對(duì)象的表現(xiàn)總是會(huì)與 ES5 的嚴(yán)格模式一致,無(wú)論此時(shí)函數(shù)是否明確運(yùn)行在嚴(yán)格模式下。

// 非嚴(yán)格模式
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");
//輸出
1
true
false
false
false

此時(shí)arguments.length =1 ,因?yàn)橹唤o mixArgs() 傳遞了一個(gè)參數(shù)。這也意味著arguments[1] 的值是 undefined ,符合將單個(gè)參數(shù)傳遞給函數(shù)時(shí)的預(yù)期;這同時(shí)意味著first 與 arguments[0] 是相等的。改變 first 和 second 的值不會(huì)對(duì) arguments 對(duì)象造成影響,無(wú)論是否在嚴(yán)格模式下,所以你可以始終依據(jù) arguments 對(duì)象來(lái)反映初始調(diào)用狀態(tài)。

默認(rèn)參數(shù)表達(dá)式

參數(shù)不僅可以設(shè)置默認(rèn)值為字符串,數(shù)字,數(shù)組或者對(duì)象,還可以是一個(gè)函數(shù)。

function add() {
  return 10
}
function a(num = add()){
  console.log(num)
}
a() // 10
默認(rèn)參數(shù)的臨時(shí)死區(qū)

第一章我們提到了let和const什么變量的臨時(shí)死區(qū)(TDZ),默認(rèn)參數(shù)既然是參數(shù),那么也同樣有臨時(shí)死區(qū),函數(shù)的作用域是獨(dú)立的,a函數(shù)不能共享b函數(shù)的作用域參數(shù)。

//這是個(gè)默認(rèn)參數(shù)臨時(shí)死區(qū)的例子,當(dāng)初始化a時(shí),b還沒(méi)有聲明,所以第一個(gè)參數(shù)對(duì)b來(lái)說(shuō)就是臨時(shí)死區(qū)。
function add(a = b, b){
  console.log(a + b)
}
add(undefined, 2) // b is not define
處理無(wú)命名參數(shù)

上面說(shuō)的參數(shù)都是命名參數(shù),而無(wú)命名參數(shù)也是函數(shù)傳參時(shí)經(jīng)常用到的。當(dāng)傳入的參數(shù)是一個(gè)對(duì)象,不是一個(gè)具體的參數(shù)名,則是無(wú)命名參數(shù)。

function add(object){
  console.log(object.a + object.b)
}
let obj = {
  a: 1,
  b: 2
}
add(obj) // 3
不定參數(shù)

使用...(展開(kāi)運(yùn)算符)的參數(shù)就是不定參數(shù),它表示一個(gè)數(shù)組。

function add(...arr){
  console.log(a + b)
}
let a = 1,b = 2
add(a, b) // 3

不定參數(shù)的使用限制:

函數(shù)只能有一個(gè)剩余參數(shù),并且它必須被放在最后

//錯(cuò)誤的寫(xiě)法1
function add(...arr, c){
  console.log(a + b)
}
let a = 1,b = 2,c = 3
add(a, b, c)

剩余參數(shù)不能在對(duì)象字面量的 setter 屬性中使用

//錯(cuò)誤的寫(xiě)法2
let obj = {
  set add(...arr) {
  
  }
}

剩余參數(shù)如何影響 arguments 對(duì)象
arguments 對(duì)象在函數(shù)被調(diào)用時(shí)反映了傳入的參數(shù),與剩余參數(shù)能協(xié)同工作,就像如下程序所演示的:

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");
//輸出
2
2
a a
b b

arguments 對(duì)象總能正確反映被傳入函數(shù)的參數(shù),而無(wú)視剩余參數(shù)的使用。

ES6中的構(gòu)造函數(shù)Function新增了支持默認(rèn)參數(shù)和不定參數(shù)。

擴(kuò)展運(yùn)算符

考慮一下Math.max()方法,它接受任意數(shù)量的參數(shù),并會(huì)返回其中的最大值。

//兩個(gè)值進(jìn)行比較
let value1 = 25,
value2 = 50;
console.log(Math.max(value1, value2)); // 50
//一個(gè)數(shù)組中找到最大值(es5)
let values = [25, 50, 75, 100]
console.log(Math.max.apply(Math, values)); 
//es6
let values = [25, 50, 75, 100]
// 等價(jià)于 console.log(Math.max(25, 50, 75, 100));
console.log(Math.max(...values)); // 100

擴(kuò)展運(yùn)算符傳遞參數(shù)

//假設(shè)你想讓  Math.max()  返回的最小值為 0 (以防數(shù)組中混入了負(fù)值),你可以將參數(shù) 0 多帶帶傳入,并繼續(xù)為其他參數(shù)使用擴(kuò)展運(yùn)算符
let values = [-25, -50, -75, -100]
console.log(Math.max(...values, 0)); // 0
ES6 的名稱屬性

ES6 給所有函數(shù)添加了 name 屬性。

選擇合適的名稱
//函數(shù)聲明
function doSomething() {
// ...
}
//匿名函數(shù)表達(dá)式
var doAnotherThing = function() {
// ...
};
console.log(doSomething.name); // "doSomething"
console.log(doAnotherThing.name); // "doAnotherThing"
名稱屬性的特殊情況
//doSomethingElse的優(yōu)先級(jí)高于doSomething 
var doSomething = function doSomethingElse() {
// ...
};
//person.firstName  實(shí)際是個(gè) getter 函數(shù),因此它的名稱是  "get firstName"
var person = {
    get firstName() {
        return "Nicholas"
    },
    sayName: function() {
        console.log(this.name);
    }
}
console.log(doSomething.name); // "doSomethingElse"
console.log(person.sayName.name); // "sayName"
var descriptor = Object.getOwnPropertyDescriptor(person, "firstName");
console.log(descriptor.get.name); // "get firstName"
另外兩個(gè)特殊情況

使用 bind() 創(chuàng)建的函數(shù)會(huì)在名稱屬性值之前帶有"bound"前綴

使用 Function 構(gòu)造器創(chuàng)建的函數(shù),其名稱屬性則會(huì)有 "anonymous" 前綴

var doSomething = function() {
// ...
};
console.log(doSomething.bind().name); // "bound doSomething"
console.log((new Function()).name); // "anonymous"
明確函數(shù)的雙重用途

JS 為函數(shù)提供了兩個(gè)不同的內(nèi)部方法: [[Call]] 與 [[Construct]] 。當(dāng)函數(shù)未使用 new進(jìn)行調(diào)用時(shí), [[call]] 方法會(huì)被執(zhí)行,運(yùn)行的是代碼中顯示的函數(shù)體。而當(dāng)函數(shù)使用 new進(jìn)行調(diào)用時(shí), [[Construct]] 方法則會(huì)被執(zhí)行,負(fù)責(zé)創(chuàng)建一個(gè)被稱為新目標(biāo)的新的對(duì)象,并
且使用該新目標(biāo)作為 this 去執(zhí)行函數(shù)體。擁有 [[Construct]] 方法的函數(shù)被稱為構(gòu)造器。

在 ES5 中判斷函數(shù)如何被調(diào)用

使用instanceof

function Person(name) {
    if (this instanceof Person) {
        this.name = name; // 使用 new
    } else {
        throw new Error("You must use new with Person.")
    }
}
var person = new Person("Nicholas");
var notAPerson = Person("Nicholas"); // 拋出錯(cuò)誤

但這種情況下并不可靠:

function Person(name) {
    if (this instanceof Person) {
        this.name = name; // 使用 new
    } else {
        throw new Error("You must use new with Person.")
    }
}
var person = new Person("Nicholas");
var notAPerson = Person.call(person, "Michael"); // 奏效了!
new.target 元屬性

通過(guò)檢查 new.target 是否被定義,這個(gè)新的元屬性就讓你能安全地判斷函數(shù)是否被使用new進(jìn)行了調(diào)用。

function Person(name) {
    if (typeof new.target !== "undefined") {
        this.name = name; // 使用 new
    } else {
        throw new Error("You must use new with Person.")
    }
}
var person = new Person("Nicholas");
var notAPerson = Person.call(person, "Michael"); // 出錯(cuò)!

也可以檢查 new.target 是否被使用特定構(gòu)造器進(jìn)行了調(diào)用,例如以下代碼:

function Person(name) {
    if (new.target === Person) {
        this.name = name; // 使用 new
    } else {
        throw new Error("You must use new with Person.")
    }
}
function AnotherPerson(name) {
    Person.call(this, name);
}
var person = new Person("Nicholas");
var anotherPerson = new AnotherPerson("Nicholas"); // 出錯(cuò)!
警告:在函數(shù)之外使用  new.target  會(huì)有語(yǔ)法錯(cuò)誤。
塊級(jí)函數(shù) 嚴(yán)格模式的塊級(jí)函數(shù)
"use strict";
if (true) {
    // 在 ES5 會(huì)拋出語(yǔ)法錯(cuò)誤, ES6 則不會(huì)
    function doSomething() {
    // ...
    }
}

塊級(jí)函數(shù)會(huì)被提升到定義所在的代碼塊的頂部:

"use strict";
if (true) {
    console.log(typeof doSomething); // "function"
    function doSomething() {
    // ...
}
doSomething();
}
console.log(typeof doSomething); // "undefined"

let 函數(shù)表達(dá)式:

"use strict";
if (true) {
    console.log(typeof doSomething); // 拋出錯(cuò)誤
    let doSomething = function () {
        // ...
    }
doSomething();
}
console.log(typeof doSomething);
非嚴(yán)格模式的塊級(jí)函數(shù)

ES6 在非嚴(yán)格模式下同樣允許使用塊級(jí)函數(shù),但行為有細(xì)微不同。塊級(jí)函數(shù)的作用域會(huì)被提升到所在函數(shù)或全局環(huán)境的頂部,而不是代碼塊的頂部。

// ES6 behavior
if (true) {
    console.log(typeof doSomething); // "function"
    function doSomething() {
    // ...
    }
doSomething();
}
console.log(typeof doSomething); // "function"
箭頭函數(shù)

箭頭函數(shù)與傳統(tǒng)的 JS 函數(shù)區(qū)別:

沒(méi)有 this 、 super 、 arguments ,也沒(méi)有 new.target 綁定

不能被使用 new 調(diào)用

沒(méi)有原型: 既然不能對(duì)箭頭函數(shù)使用 new ,那么它也不需要原型,也就是沒(méi)有prototype 屬性。

不能更改 this : this 的值在函數(shù)內(nèi)部不能被修改,在函數(shù)的整個(gè)生命周期內(nèi)其值會(huì)保持不變

沒(méi)有 arguments 對(duì)象

不允許重復(fù)的具名參數(shù)

箭頭函數(shù)語(yǔ)法

無(wú)參數(shù)

var getName = () => "Nicholas";
// 有效等價(jià)于:
var getName = function() {
    return "Nicholas";
};

單個(gè)參數(shù)

var reflect = value => value;
// 有效等價(jià)于:
var reflect = function(value) {
    return value;
};

多個(gè)參數(shù)

var sum = (num1, num2) => num1 + num2;
// 有效等價(jià)于:
var sum = function(num1, num2) {
    return num1 + num2;
};

多個(gè)函數(shù)語(yǔ)句體

var sum = (num1, num2) => {
    return num1 + num2;
};
// 有效等價(jià)于:
var sum = function(num1, num2) {
    return num1 + num2;
};

//將對(duì)象字面量包裹在括號(hào)內(nèi),標(biāo)示了括號(hào)內(nèi)是一個(gè)字面量而不是函數(shù)體。
var getTempItem = id => ({ id: id, name: "Temp" });
// 有效等價(jià)于:
var getTempItem = function(id) {
    return {
        id: id,
        name: "Temp"
    };
};
創(chuàng)建立即調(diào)用函數(shù)表達(dá)式

傳統(tǒng)函數(shù)

let person = function(name) {
    return {
        getName: function() {
            return name;
        }
    };
}("Nicholas");
console.log(person.getName()); // "Nicholas"

箭頭函數(shù)

let person = ((name) => {
    return {
    getName: function() {
        return name;
    }
};
})("Nicholas");
console.log(person.getName()); // "Nicholas"
譯注:使用傳統(tǒng)函數(shù)時(shí),  (function(){/函數(shù)體/})();  與  (function(){/函數(shù)體/}());
這兩種方式都是可行的。
但若使用箭頭函數(shù),則只有下面的寫(xiě)法是有效的: (() => {/函數(shù)體/})();
尾調(diào)用優(yōu)化

尾調(diào)用是指在函數(shù)return的時(shí)候調(diào)用一個(gè)新的函數(shù),由于尾調(diào)用的實(shí)現(xiàn)需要存儲(chǔ)到內(nèi)存中,在一個(gè)循環(huán)體中,如果存在函數(shù)的尾調(diào)用,你的內(nèi)存可能爆滿或溢出。

ES6中,引擎會(huì)幫你做好尾調(diào)用的優(yōu)化工作,你不需要自己優(yōu)化,但需要滿足下面3個(gè)要求:

1、函數(shù)不是閉包

2、尾調(diào)用是函數(shù)最后一條語(yǔ)句

3、尾調(diào)用結(jié)果作為函數(shù)返回

一個(gè)滿足以上要求的函數(shù)如下所示:

"use strict";   
function a() {
  return b();
}

下面的都是不滿足的寫(xiě)法:

//沒(méi)有return不優(yōu)化
"use strict";
function a() {
  b();
}

//不是直接返回函數(shù)不優(yōu)化
"use strict";
function a() {
  return 1 + b();
}

//尾調(diào)用是函數(shù)不是最后一條語(yǔ)句不優(yōu)化
"use strict";
function a() {
  const s = b();
  return s
}

//閉包不優(yōu)化
"use strict";
function a() {
  const num = 1
  function b() {
    return num
  }
  return b
}

尾調(diào)用實(shí)際用途——遞歸函數(shù)優(yōu)化

在ES5時(shí)代,我們不推薦使用遞歸,因?yàn)檫f歸會(huì)影響性能。
但是有了尾調(diào)用優(yōu)化之后,遞歸函數(shù)的性能有了提升。

//新型尾優(yōu)化寫(xiě)法
"use strict";  
function a(n, p = 1) {
  if(n <= 1) {
    return 1 * p
  }
  let s = n * p
  return a(n - 1, s)
}
//求 1 x 2 x 3的階乘
let sum = a(3)
console.log(sum) // 6

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

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

相關(guān)文章

  • 深入理解ES6筆記——導(dǎo)讀

    摘要:最近買了深入理解的書(shū)籍來(lái)看,為什么學(xué)習(xí)這么久還要買這本書(shū)呢主要是看到核心團(tuán)隊(duì)成員及的創(chuàng)造者為本書(shū)做了序,作為一個(gè)粉絲,還是挺看好這本書(shū)能給我?guī)?lái)一個(gè)新的升華,而且本書(shū)的作者也非常厲害。 使用ES6開(kāi)發(fā)已經(jīng)有1年多了,以前看的是阮一峰老師的ES6教程,也看過(guò)MDN文檔的ES6語(yǔ)法介紹。 最近買了《深入理解ES6》的書(shū)籍來(lái)看,為什么學(xué)習(xí)ES6這么久還要買這本書(shū)呢?主要是看到Daniel A...

    Godtoy 評(píng)論0 收藏0
  • 深入理解JavaScript

    摘要:深入之繼承的多種方式和優(yōu)缺點(diǎn)深入系列第十五篇,講解各種繼承方式和優(yōu)缺點(diǎn)。對(duì)于解釋型語(yǔ)言例如來(lái)說(shuō),通過(guò)詞法分析語(yǔ)法分析語(yǔ)法樹(shù),就可以開(kāi)始解釋執(zhí)行了。 JavaScript深入之繼承的多種方式和優(yōu)缺點(diǎn) JavaScript深入系列第十五篇,講解JavaScript各種繼承方式和優(yōu)缺點(diǎn)。 寫(xiě)在前面 本文講解JavaScript各種繼承方式和優(yōu)缺點(diǎn)。 但是注意: 這篇文章更像是筆記,哎,再讓我...

    myeveryheart 評(píng)論0 收藏0
  • 深入理解ES6筆記(十一)Promise與異步編程

    摘要:回調(diào)函數(shù)模式類似于事件模型,因?yàn)楫惒酱a也會(huì)在后面的一個(gè)時(shí)間點(diǎn)才執(zhí)行如果回調(diào)過(guò)多,會(huì)陷入回調(diào)地獄基礎(chǔ)可以當(dāng)做是一個(gè)占位符,表示異步操作的執(zhí)行結(jié)果。函數(shù)可以返回一個(gè),而不必訂閱一個(gè)事件或者向函數(shù)傳遞一個(gè)回調(diào)函數(shù)。 主要知識(shí)點(diǎn):Promise生命周期、Promise基本操作、Promise鏈、響應(yīng)多個(gè)Promise以及集成PromiseshowImg(https://segmentfaul...

    RayKr 評(píng)論0 收藏0
  • 深入理解ES6筆記(十)增強(qiáng)的數(shù)組功能

    摘要:在可迭代對(duì)象上使用所有數(shù)組上的新方法與方法與方法均接受兩個(gè)參數(shù)一個(gè)回調(diào)函數(shù)一個(gè)可選值用于指定回調(diào)函數(shù)內(nèi)部的?;卣{(diào)函數(shù)可接收三個(gè)參數(shù)數(shù)組的某個(gè)元素該元素對(duì)應(yīng)的索引位置以及該數(shù)組自身。 主要知識(shí)點(diǎn):創(chuàng)建數(shù)組、數(shù)組上的新方法、類型化數(shù)組showImg(https://segmentfault.com/img/bVbfWo1?w=991&h=587); 《深入理解ES6》筆記 目錄 創(chuàng)建數(shù)組...

    pekonchan 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<