摘要:錯誤的寫法錯誤的寫法中的構造函數新增了支持默認參數和不定參數。箭頭函數的簡單理解箭頭函數的左邊表示輸入的參數,右邊表示輸出的結果。但是有了尾調用優化之后,遞歸函數的性能有了提升。
作為前端切圖仔,越發覺得自己離不開函數了。
說到JavaScript函數,腦子里都是匿名函數、普通函數、閉包函數、構造函數......然后還能說出一大堆函數的概念。如果你達到這個水平,那么函數對你來說沒有難度,是一個前端老鳥了。
當我閉上眼睛,不看鍵盤,手指在鍵盤上敲擊出一個排序函數的時候,我在想,還是回顧一下函數的基本知識才有意思。
函數的默認參數在ES5中,我們給函數傳參數,然后在函數體內設置默認值,如下面這種方式。
function a(num, callback) { num = num || 6 callback = callback || function (data) {console.log("ES5: ", data)} callback(num * num) } a() //ES5: 36,不傳參輸出默認值 //你還可以這樣使用callback a(10, function(data) { console.log(data * 10) // 1000, 傳參輸出新數值 })
而在ES6中,我們使用新的默認值寫法。
function a(num = 6, callback = function (data) {console.log("ES6: ", data)}) { callback(num * num) } a() //ES6: 36, 不傳參輸出默認值 a(10, function(data) { console.log(data * 10) // 1000,傳參輸出新數值 })
使用ES6的默認值寫法可以讓函數體內部的代碼更加簡潔優雅
默認值對arguments對象的影響
我們先要了解arguments對象是什么?準確一點來說它是一個類數組對象,它存在函數內部,它將當前函數的所有參數組成了一個類數組對象。
function a(num, b){ console.log(arguments) // {"0": 6, "1": 10} console.log(arguments.length) // 2 } a(6, 10)
上面的輸出結果看起來很正常,那么,如果我們加上參數默認值會怎樣呢?
function a(num = 1, b = 1){
console.log(arguments)
}
a() // {} 默認值不能被arguments識別。
a(6, 10) // {"0":6,"1":10}
下面我們看一下修改參數默認值對arguments的影響。
1、在ES5的非嚴格模式下,一開始輸入的參數是1,那么可以獲取到arguments[0](表示第一個參數)全等于num,修改num = 2之后,arguments[0]也能更新到2。
function a(num){ console.log(num === arguments[0]) //true num = 2 //修改參數默認值 console.log(num === arguments[0]) //true } a(1)
2、在ES5的非嚴格模式下,arguments就不能在函數內修改默認值后跟隨著跟新了。
"use strict"; //嚴格模式 function a(num) { console.log(num === arguments[0]); // true num = 2; console.log(num === arguments[0]); // false } a(1);
在ES6環境下,默認值對arguments的影響和ES5嚴格模式是同樣的標準。
默認參數表達式
參數不僅可以設置默認值為字符串,數字,數組或者對象,還可以是一個函數。
function add() { return 10 } function a(num = add()){ console.log(num) } a() // 10
默認參數的臨時死區
第一章我們提到了let和const什么變量的臨時死區(TDZ),默認參數既然是參數,那么也同樣有臨時死區,函數的作用域是獨立的,a函數不能共享b函數的作用域參數。
//這是個默認參數臨時死區的例子,當初始化a時,b還沒有聲明,所以第一個參數對b來說就是臨時死區。 function add(a = b, b){ console.log(a + b) } add(undefined, 2) // b is not define無命名參數
上面說的參數都是命名參數,而無命名參數也是函數傳參時經常用到的。當傳入的參數是一個對象,不是一個具體的參數名,則是無命名參數。
function add(object){ console.log(object.a + object.b) } let obj = { a: 1, b: 2 } add(obj) // 3
不定參數的使用:使用...(展開運算符)的參數就是不定參數,它表示一個數組。
function add(...arr){ console.log(a + b) } let a = 1,b = 2 add(a, b) // 3
不定參數的使用限制:必須放在所有參數的末尾,不能用于對象字面量setter中。
//錯誤的寫法1 function add(...arr, c){ console.log(a + b) } let a = 1,b = 2,c = 3 add(a, b, c) //錯誤的寫法2 let obj = { set add(...arr) { } }
ES6中的構造函數Function新增了支持默認參數和不定參數。
展開運算符(...)展開運算符的作用是解構數組,然后將每個數組元素作為函數參數。
有了展開運算符,我們操作數組的時候,就可以不再使用apply來指定上下文環境了。
//ES5的寫法 let arr = [10, 20, 50, 40, 30] let a = Math.max.apply(null, arr) console.log(a) // 50 //ES6的寫法 let arr = [10, 20, 50, 40, 30] let a = Math.max(...arr) console.log(a) // 50塊級函數
嚴格模式下:在ES6中,你可以在塊級作用域內聲明函數,該函數的作用域只限于當前塊,不能在塊的外部訪問。
"use strict"; if(true) { const a = function(){ } }
非嚴格模式:即使在ES6中,非嚴格模式下的塊級函數,他的作用域也會被提升到父級函數的頂部。所以大家寫代碼盡量使用嚴格模式,避免這些奇葩情況。
箭頭函數(=>)如果看到你這里,你發現你還沒有在項目中使用過箭頭函數,沒關系,你并不low,而是學習不夠努力。
const arr = [5, 10] const s = arr.reduce((sum, item) => sum + item) console.log(s) // 15
箭頭函數和普通函數的區別是:
1、箭頭函數沒有this,函數內部的this來自于父級最近的非箭頭函數,并且不能改變this的指向。
2、箭頭函數沒有super
3、箭頭函數沒有arguments
4、箭頭函數沒有new.target綁定。
5、不能使用new
6、沒有原型
7、不支持重復的命名參數。
箭頭函數的簡單理解
1、箭頭函數的左邊表示輸入的參數,右邊表示輸出的結果。
const s = a => a console.log(s(2)) // 2
2、箭頭函數中,最重要的this報錯將不再成為你每天都擔心的bug。
3、箭頭函數還可以輸出對象,在react的action中就推薦這種寫法。
const action = (type, a) => ({ type: "TYPE", a })
4、支持立即執行函數表達式寫法
const test = ((id) => { return { getId() { console.log(id) } } })(18) test.getId() // 18
5、箭頭函數給數組排序
const arr = [10, 50, 30, 40, 20] const s = arr.sort((a, b) => a - b) console.log(s) // [10,20,30,40,50]尾調用優化
尾調用是什么鬼?
尾調用是指在函數return的時候調用一個新的函數,由于尾調用的實現需要存儲到內存中,在一個循環體中,如果存在函數的尾調用,你的內存可能爆滿或溢出。
ES6中,引擎會幫你做好尾調用的優化工作,你不需要自己優化,但需要滿足下面3個要求:
1、函數不是閉包
2、尾調用是函數最后一條語句
3、尾調用結果作為函數返回
一個滿足以上要求的函數如下所示:
"use strict"; function a() { return b(); }
下面的都是不滿足的寫法:
//沒有return不優化 "use strict"; function a() { b(); } //不是直接返回函數不優化 "use strict"; function a() { return 1 + b(); } //尾調用是函數不是最后一條語句不優化 "use strict"; function a() { const s = b(); return s } //閉包不優化 "use strict"; function a() { const num = 1 function b() { return num } return b }
尾調用實際用途——遞歸函數優化
在ES5時代,我們不推薦使用遞歸,因為遞歸會影響性能。
但是有了尾調用優化之后,遞歸函數的性能有了提升。
//新型尾優化寫法 "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總結
函數這一章涉及到的知識點比較多,默認參數,命名參數,不定參數,展開運算符,箭頭函數,尾調用優化。
第一次學習這些知識的人可以關注箭頭函數和展開運算符的使用,這是最重要也最常用的知識,如果你已經在項目中使用過這些知識,那么作為鞏固也是有幫助的,俗話說溫故知新。
=> 返回文章目錄
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/84056.html
摘要:在可迭代對象上使用所有數組上的新方法與方法與方法均接受兩個參數一個回調函數一個可選值用于指定回調函數內部的。回調函數可接收三個參數數組的某個元素該元素對應的索引位置以及該數組自身。 主要知識點:創建數組、數組上的新方法、類型化數組showImg(https://segmentfault.com/img/bVbfWo1?w=991&h=587); 《深入理解ES6》筆記 目錄 創建數組...
摘要:和都能夠聲明塊級作用域,用法和是類似的,的特點是不會變量提升,而是被鎖在當前塊中。聲明常量,一旦聲明,不可更改,而且常量必須初始化賦值。臨時死區臨時死區的意思是在當前作用域的塊內,在聲明變量前的區域叫做臨時死區。 主要知識點有:var變量提升、let聲明、const聲明、let和const的比較、塊級綁定的應用場景showImg(https://segmentfault.com/img...
摘要:將對象的屬性拷貝到了對象,合并成一個新的對象。而這種行為也是新增的標準。總結本章講解了對象字面量語法拓展,新增方法,允許重復的對象字面量屬性,自有枚舉屬性排序,增強對象原型,明確了方法的定義。但是,就算把全部新增的功能記住也不是難事。 變量功能被加強了、函數功能被加強了,那么作為JavaScript中最普遍的對象,不加強對得起觀眾嗎? 對象類別 在ES6中,對象分為下面幾種叫法。(不需...
摘要:創建數組中創建數組的方式數組字面量一個數組。傳入一個回調函數,找到數組中符合當前搜索規則的第一個元素,返回它,并且終止搜索。用新元素替換掉數組內的元素,可以指定替換下標范圍。 ES5提供的數組已經很強大,但是ES6中繼續改進了一些,主要是增加了新的數組方法,所以這章的知識非常少。 創建數組 ES5中創建數組的方式:數組字面量、new一個數組。 const arr1 = [] //數組字...
閱讀 3793·2021-09-29 09:34
閱讀 3770·2021-09-27 13:34
閱讀 565·2021-09-24 09:47
閱讀 3036·2019-08-30 15:53
閱讀 1808·2019-08-26 13:54
閱讀 2084·2019-08-26 13:43
閱讀 530·2019-08-23 14:47
閱讀 1739·2019-08-23 14:28