摘要:如果所有函數都是尾調用,那么完全可以做到每次執行時,調用幀只有一項,這將大大節省內存。等同于等同于注意,只有不再用到外層函數的內部變量,內層函數的調用幀才會取代外層函數的調用幀,否則就無法進行尾調用優化。
1. 函數參數的默認值
在ES6之前是不能為函數的參數指定默認值的,要想實現默認值只能通過判斷賦值的方式來實現,在ES6中允許函數為參數設置默認值,主要是為了提高代碼的可閱讀性,有利于代碼的優化。另外注意的是在參數賦值的時候,該參數不能重復使用,不能使用let const 進行定義。
// ES6 之前實現 function log(x, y) { y = y || "World"; if (typeof y === "undefined") { y = "World"; } console.log(x, y); } log("Hello") // Hello World log("Hello", "China") // Hello China log("Hello", "") // Hello World // ES6 中實現 function log(x, y = "World") { console.log(x, y); } log("Hello") // Hello World log("Hello", "China") // Hello China log("Hello", "") // Hello function Point(x = 0, y = 0) { this.x = x; this.y = y; } const p = new Point(); p // { x: 0, y: 0 } function foo(x = 5,x) { let x = 1; // 報錯,不能同名參數,不能對參數進行let const 定義 const x = 2; }
如果函數在調用的時候沒有提供參數,內部變量就不會產生,就會產生錯誤,通過提供函數的默認值可以解決這種問題,如下:
function foo({x, y = 5}) { console.log(x, y); } foo() // 報錯 foo({x:1}) // 1 5 foo({x:2,y:3) // 2 3 foo({}) // undefined 5 function foo ({x,y = 5} = {}){ console.log(x,y) } foo() // undefined 5 這樣就是如果沒有在調用的時候傳值 就默認賦空對象。
如下例子:
function post(url, {b = "",type="get",h={}}){ console.log(type) } post("w.b.c",{}) // get post("w.b.c") // 報錯 // 改成這樣就可以了 function post(url, {b = "",type="get",h={}} = {}){ console.log(type) } post("w.b.c",{}) // get post("w.b.c") // get
下面例子的區別
// 寫法一 function m1({x = 0, y = 0} = {}) { return [x, y]; } // 寫法二 function m2({x, y} = { x: 0, y: 0 }) { return [x, y]; } 兩個都是有默認值在調用的時候都傳值或者都不傳值的時候情況是一樣的。 但是如果傳空值,或者不傳值的情況會有差異如下: m1({}) // 因為本身有默認值 所以為 [0,0] m2({}) // 默認值為空 解構賦值沒有傳值 所以 [undefined,undefined] // 其他情況同上 m1({x: 3}) // [3, 0] m2({x: 3}) // [3, undefined] m1({z: 3}) // [0, 0] m2({z: 3}) // [undefined, undefined]
如果定義了默認值的參數,應該是函數的尾參數。而且這個參數是無法省略的,除非輸入undefined
函數參數指定了默認值之后,函數的length屬性將會減去指定了默認值的參數個數。因為該屬性認為,指定了默認值的參數將不包含在預期參數個數中。如下:
(function (a) {}).length // 1 (function (a = 5) {}).length // 0 (function (a, b, c = 5) {}).length // 2
如果函數中的參數設置了默認值,那么函數在聲明初始化的時候,參數會形成一個多帶帶的作用域,初始化完成后這個作用域就會消失,這種情況只在參數設置了默認值的情況下。如下:
var x = 1; function f(x, y = x) { console.log(y); } f(2) // 2 // 因為 設置了默認值 所以在調用 f 的時候就形成了作用域,這時候因為將x賦值給y 傳入的x 為 2 所以y是2,如果這時候 調用的時候不傳值, 那么x將指向全局,所以y = 1
利用參數默認值,可以指定某一個參數不得省略,如果省略就報錯,如下
function throwIfMissing() { throw new Error("Missing parameter"); } function foo(mustBeProvided = throwIfMissing()) { return mustBeProvided; } foo() // Error: Missing parameter foo(2) // 22. rest 參數
ES6 中 增加了 rest 參數(...變量名),用于獲取函數多余的參數,rest參數搭配的變量是一個數組,該變量將多余的參數放入數組中。
function add(...values) { let sum = 0; for (var val of values) { sum += val; } return sum; } add(2, 5, 3) // 10 // 注意:rest 參數之后不能再有其他參數,另外rest參數也不計算在 函數的length屬性中。3. 嚴格模式
ES6 中,如果函數參數使用了默認值,解構賦值,或者擴展運算符,那么函數內部將不能顯式設定為嚴格模式,否則會報錯。因為函數執行的時候 先執行函數參數,在執行函數體,但是因為只有在函數體中才能知道參數是否以嚴格模式執行,但是參數卻應該先于函數執行。有兩種方法可以規避:一、 設置全局嚴格模式,二、把函數包在一個無參數的立即執行函數里面。4. name屬性
返回函數的函數名,如下:
function foo(){} foo.name // foo var f = function(){} // ES5 f.name // "" // ES6 f.name // f var f = function c(){} f.name // c5. 箭頭函數
ES6 允許使用 “箭頭” (=>)定義函數
var f = v => v; // 等同于 var f = function (v) { return v; }; var f = () => 5; // 等同于 var f = function () { return 5 }; var sum = (num1, num2) => num1 + num2; // 等同于 var sum = function(num1, num2) { return num1 + num2; }; // 如果箭頭函數后面的語句較多就要用大括號包裹起來 并return返回 var sum = (num1, num2) => { return num1 + num2; //rest 參數與箭頭函數結合的例子。 const numbers = (...nums) => nums; numbers(1, 2, 3, 4, 5) // [1,2,3,4,5] const headAndTail = (head, ...tail) => [head, tail]; headAndTail(1, 2, 3, 4, 5) // [1,[2,3,4,5]]
1. 函數體內的this對象,就是在定義時所在的對象,而不是使用時所在的對象。 2. 不可以當作構造函數,也就是說,不可以使用new命令,否則會拋出一個錯誤。 3. 不可以使用arguments對象,該對象在函數體內不存在。如果要用,可以用 rest 參數代替。 4. 不可以使用yield命令,因此箭頭函數不能用作 Generator 函數。 5. 由于箭頭函數沒有自己的this,所以當然也就不能用call()、apply()、bind()這些方法去改變this的指向。
1. 定義對象的方法,且該方法內部包括this 2. 動態定義this 的場合,如點擊事件中this 的指向
箭頭函數內部可以在嵌套使用箭頭函數。6. 尾調用優化
函數式編程的一個重要概念,指某個函數的最后一步是調用另一個函數
function f(x){ return g(x); } // 一下都不屬于 // 情況一 function f(x){ let y = g(x); return y; } // 情況二 function f(x){ return g(x) + 1; } // 情況三 function f(x){ g(x); }
只保留內層函數的調用幀。如果所有函數都是尾調用,那么完全可以做到每次執行時,調用幀只有一項,這將大大節省內存。這就是“尾調用優化”的意義。
function f() { let m = 1; let n = 2; return g(m + n); } f(); // 等同于 function f() { return g(3); } f(); // 等同于 g(3);
注意,只有不再用到外層函數的內部變量,內層函數的調用幀才會取代外層函數的調用幀,否則就無法進行“尾調用優化”。
函數調用自身,稱為遞歸。如果尾調用自身,就稱為尾遞歸。
在正常模式下,可以使用減少調用棧,采用循環換掉遞歸的方法歡迎關注 公眾號【小夭同學】
ES6入門系列
ES6入門之let、cont
ES6入門之變量的解構賦值
ES6入門之字符串的擴展
ES6入門之正則的擴展
ES6入門之數值的擴展
Git教程
前端Git基礎教程
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/54944.html
摘要:循環遍歷對象自身的和繼承的可枚舉屬性不含屬性。返回一個數組,包含對象自身的所有屬性的鍵名。目前,只有對象方法的簡寫法可以讓引擎確認,定義的是對象的方法。showImg(https://user-gold-cdn.xitu.io/2019/5/21/16ada8456223b0e1); 1. 屬性的簡潔表示法 在ES6中 允許直接寫入變量和函數,作為對象的屬性和方法,使得代碼的書寫更為簡潔。...
摘要:屬性的簡潔表示法在中允許直接寫入變量和函數,作為對象的屬性和方法,使得代碼的書寫更為簡潔。循環遍歷對象自身的和繼承的可枚舉屬性不含屬性。返回一個數組,包含對象自身的所有屬性的鍵名。 showImg(https://segmentfault.com/img/remote/1460000019259004?w=1282&h=1920); 1. 屬性的簡潔表示法 在ES6中 允許直接寫入變量...
摘要:如果所有函數都是尾調用,那么完全可以做到每次執行時,調用幀只有一項,這將大大節省內存。等同于等同于注意,只有不再用到外層函數的內部變量,內層函數的調用幀才會取代外層函數的調用幀,否則就無法進行尾調用優化。 showImg(https://segmentfault.com/img/bVbrTHp?w=1080&h=1920); 1. 函數參數的默認值 1.1 用法 在ES6之前是不能為...
showImg(https://user-gold-cdn.xitu.io/2019/5/22/16adcec448a45d82); 1. Object.is() 用來解決在ES5中 兩種相等運算符的缺點。用來比較兩個值是否嚴格相等,行為和(===)基本一致。 在ES5中判斷兩個值是否相等,只能用(==)相等運算符和(===)嚴格相等運算符,但是這兩貨都有缺點,前者 兩邊的值都會轉換數據類型,...
閱讀 1167·2021-10-20 13:48
閱讀 2173·2021-09-30 09:47
閱讀 3103·2021-09-28 09:36
閱讀 2342·2019-08-30 15:56
閱讀 1195·2019-08-30 15:52
閱讀 2020·2019-08-30 10:48
閱讀 606·2019-08-29 15:04
閱讀 564·2019-08-29 12:54