摘要:正式因為它沒有,所以也就不能用作構造函數。函數的最后一步是調用函數,這就叫尾調用尾遞歸函數調用自身,稱為遞歸。它的參數是一個回調函數,所有數組成員依次執行該回調函數,直到找出第一個返回值為的成員,然后返回該成員。
這是ES6的入門篇教程的筆記,網址:鏈接描述,以下內容中粗體+斜體表示大標題,粗體是小標題,還有一些重點;斜體表示對于自身,還需要下功夫學習的內容。這里面有一些自己的見解,所以若是發現問題,歡迎指出~
上一篇es5的到最后令人崩潰,看來深層的東西還是不太熟,希望這次不要這樣了!!!
函數的擴展
1、函數參數的默認值
基本用法
ES6之前,不能直接為函數的參數指定默認值,只能采用變通的方法。
參數默認值不是傳值的,而是每次都重新計算默認值表達式的值。也就是說,參數默認值是惰性求值的。
function log(x, y) { y = y || "World"; console.log(x, y); } log("Hello", "") // Hello World 后一個字段是本意是空字符,也會被賦值為"World" // 改進一下,賦值時為以下 if (typeof y === "undefined") { y = "World"; } // ES6允許為函數的參數設置默認值,即直接寫在參數定義的后面 function log(x, y = "World") { console.log(x, y); } log("Hello") // Hello World log("Hello", "China") // Hello World log("Hello", "") // Hello let x = 99; function foo(p = x + 1) { console.log(p); } foo() // 100 x = 100; foo() // 101 這就是惰性求值,參數p的默認值是x+1,每次調用函數foo,都會重新計算x + 1,而不是默認p等于100
與解構賦值默認值結合使用
參數默認值可以與解構賦值的默認值,結合起來使用。
function foo({x, y = 5}) { // 只用了對象的結構賦值默認值,沒有使用函數參數的默認值。 console.log(x, y); } foo({}) // undefined 5 foo() // TypeError: Cannot read prototype "x" of undefined function foo({x, y = 5} = {}) { // 如果沒有提供參數,函數foo的參數默認為一個空對象。 console.log(x, y); } foo() // undefined 5
有點要繞暈了,下面這個是重點,如果能知道兩者的區別,說明就已經理解了。
// 第一種 function m1({x = 0, y = 0} = {}) { return [x, y]; } // 第二種 function m2({x, y} = {x: 0, y: 0}) { return [x, y]; }
上面的這兩種寫法都對函數的參數設定了默認值,區別在于第一種行數參數的默認值是空對象,但是這是了對象解構賦值的默認值;第二種函數參數的默認值是一個有具體屬性的對象,但是沒有設置對象解構賦值的默認值。
一起看看它們的輸出情況。
// 函數沒有參數的情況 m1() // [0, 0] m2() // [0, 0] // x有值,y無值的情況 m1({x: 3}) // [3, 0] m2({x: 3}) // [3, undefined] // x和y都無值的情況 m1({}) // [0, 0] m2({}) // [undefined, undefined] // 綜上,推薦第一種寫法,當然按需寫更好
參數默認值的位置
通常情況下,定義了默認值的參數,應該是函數的尾參數。因為這樣比較容易看出來,到底省略了那些參數。如果非尾部的參數設置默認值,實際上這個參數是沒法省略的,除非顯式輸入undefined。
// function f(x = 1, y) { return [x, y]; } f() // [1, undefined] f(2) // [2, undefined] f(, 1) // 報錯 f(undefined, 1) // [1, 1]
作用域
一旦設置了參數的默認值,函數進行聲明初始化時,參數會形成一個多帶帶的作用域(context)。等到初始化結束,這個作用域就會消失。這種語法行為,再不設置參數默認值時,是不會出現的。
let x = 1; function f(y = x) { // 參數y = x形成一個多帶帶的作用域,在這個作用域里面,變量x本身沒有定義,所以指向外層的全局變量x let x = 2; // 函數調用時,函數體內部的局部變量x影響不到默認值變量x console.log(y) } f() // 1 // 如果此時,全局變量x不存在,就會報錯 function f(y = x) { let x = 2; console.log(y); } f() // ReferenceError: x is not defined
2、rest參數
ES6引入rest參數(形式為...變量名),用于獲取函數的多余參數,這樣就不需要arguments對象了。rest參數搭配的變量時一個數組,該變量將多余的參數放入數組中。
注:rest參數之后不能再有其他參數(即只能是最后一個參數),否則會報錯。
函數的length屬性,不包括rest參數。
function add(...values) { // 利用rest參數,可以向該函數傳入任意數目的參數 let sum = 0; for(let val of values) { sum += val; } return sum; } add(2, 5, 3) // 10 // 利用rest參數改寫數組push方法 function push(array, ...items) { items.forEach(function(item) { array.push(item); console.log(item); }) } let a = []; push(a, 1, 2, 3); // rest參數之后不能再有其他參數 // 報錯 function f(a, ...b, c) { // ... }
5、箭頭函數
基本用法
ES6允許使用“箭頭”(=>)定義函數。
如果箭頭函數不需要參數或需要多個參數,就使用一個圓括號代表參數部分。
如果箭頭函數的代碼塊部分多于一條語句,就要使用大括號將它們括起來,并且使用return語句返回。
注:函數體內的this對象,就是定義時所在的對象,而不是使用時所在的對象(this對象的指向是可變的,但是在箭頭函數中,它是固定的);不可以當作構造函數,也就是說,不可以使用new命令,否則會拋出一個錯誤。
let f = v => v; // 等同于 let f = function (v) { return v; }; let f = () => 5; // 等同于 let f = function () { return 5 }; let sum = (num1, num2) => num1 + num2; // 等同于 let sum = function(num1, num2) { return num1 + num2; }; // 報錯 返回對象必須在對象外面加上括號,否則會報錯。 let getItem = id => { id: id, name: "Temp" }; // 不報錯 let getItem = id => ({ id: id, name: "Temp" }); // 箭頭函數可以與變量解構結合使用 const full = ({ first, last }) => first + "" + last; // 箭頭函數使得表達更加簡介 const isEven = n => n % 2 === 0; const aqure = n => n * n; // 簡化回調函數 let result = values.sort((a, b) => a-b); // 正常寫法 let result = values.sort(function (a, b) { return a - b; });
需要注意this的指向問題:箭頭函數讓this指向固定化,箭頭函數的this綁定定義時錯在的作用域,普通函數的this指向運行時所在的作用域。
let handle = { id: "123456", init: function() { document.addEventListener("click", event => this.doSomething(event.type), false); // 箭頭函數,this.doSomething中的this指向handler對象(定義時的作用域);否則的話,this指向document對象 }, doSomething: function(type) { console.log("Handling " + type + " for " + this.id); } };
this指向的固定化,并不是因為箭頭函數內部有綁定this的機制,實際原因是箭頭函數根本沒有自己的this,導致內部的this就是外層代碼塊的this。正式因為它沒有this,所以也就不能用作構造函數。
// ES6 function foo() { setTimeout(() => { console.log("id:", this.id); }, 100); } // ES5 function foo() { let _this = this; setTimeout(function () { console.log("id:", _this.id); }, 100); }
箭頭函數不適用場合
1、定義對象的方法,且該方法內部包括this。
這是因為對象不構成多帶帶的作用域,導致箭頭函數定義時的對象就是全局作用域。
const cat = { lives: 9, jumps: () => { // 箭頭函數,使得this指向全局對象,不會得到預期解構;如果是普通函數,該方法內部的this指向cat this.lives--; } }
2、需要動態this的時候,也不應使用箭頭函數。
let button = document.getElementById("press"); button.addEventListener("click", () => { this.classList.toggle("on"); });
點擊按鈕會報錯,因為button的監聽函數是一個箭頭函數,導致里面的this就是全局對象。如果改成普通函數,this就會動態指向被點擊的按鈕對象。
另外,如果函數體很復雜,有很多行,或者函數內部有大量的讀寫操作,不單純是為了計算值,這時也不應該使用箭頭函數,而是要使用普通函數,這樣可以提高代碼可讀性。
6、尾調用優化
尾調用(Tail Call)是函數式編程的一個重要概念,本身非常簡單,一句話就能說清楚,就是指某個函數的最后一步是調用另一個函數。
function f(x) { return g(x); // 函數f的最后一步是調用函數g,這就叫尾調用 }
尾遞歸
函數調用自身,稱為遞歸。如果尾調用自身,就稱為尾遞歸。
數組的擴展
含義
擴展運算符(spread)是三個點(...)。它好比rest參數的逆運算,將一個數組轉為用逗號分隔的參數序列。
console.log(1, ...[2, 3, 4], 5); // 1 2 3 4 5 // 如果擴展運算符后面是一個空數組,則不產生任何效果 [...[], 1] // [1] // 注意,只有函數調用時,擴展運算符才可以放在圓括號中,否則會報錯。前兩種報錯,是因為擴展運算符所在的括號不是函數調用。 (...[1, 2]) // Uncaught SyntaxError: Unexpected token ... console.log((...[1, 2])) // Uncaught SynaxError: Unexpexted token ... console.log(...[1, 2]) // 1 2
擴展運算符的應用
(1)復制數組
數組是復合的數據類型,直接復制的話,指數復制了指向底層數據結構的指針,而不是克隆一個全新的數組。
const a1 = [1, 2]; const a2 = a1; // a2并不是a1的克隆,而是指向同一份數據的另一個指針,修改a2,會直接導致a1的改變。 a2[0] = 2; a1; // [2, 2] // ES5復制數組 const a1 = [1, 2]; const a2 = a1.concat(); a2[0] = 2; a1 // [1, 2] // ES6的簡便寫法 const a1 = [1, 2]; const a2 = [...a1]; const [...a2] = a1; // 這兩種寫法,a2都是a1的克隆
(2)合并數組
擴展運算符提供了數組合并的新寫法。
const arr1 = ["a", "b"]; const arr2 = ["c"]; // ES5的合并數組 arr1.concat(arr1, arr2); // ES6的合并數組 [...arr1, ...arr2]; // 注意下面的合并,數組里面的元素是對象,拷貝過去的就只能是地址!!! const a1 = [{ foo: 1 }]; const a2 = [{ bar: 2 }]; const a3 = a1.concat(a2); const a4 = [...a1, ... a2]; a3[0] === a1[0]; // true a4[0] === a1[0]; // true // 拷貝過去的只有地址,也就是說,如果修改了原數組的成員,會同步反映到新數組。
(3)與解構賦值結合
擴展運算符可以與解構賦值結合起來,用于生成數組。
// ES5 a = list[0], rest = list.slice(1) // ES6 [a, ...rest] = list // 如果將擴展運算符用于數組賦值,只能放在參數的最后一位,否則會報錯 // 報錯 const [...butLast, last] = [1, 2, 3, 4, 5];
(4)字符串
擴展運算符還可以將字符串轉為真正的數組。
[..."hello"]; // ["h", "e", "l", "l", "o"]
5、數組實例的find()和findIndex()
數組實例的find方法,用于找出第一個符合條件的數組成員。它的參數是一個回調函數,所有數組成員依次執行該回調函數,直到找出第一個返回值為true的成員,然后返回該成員。如果沒有符合條件的成員,則返回undefined。接受三個參數,依次為當前的值、當前的位置和原數組。
[1, 4, -5, 10].find((n) => n < 0) // -5
數組實例的findIndex方法的用法與find方法非常類似,返回第一個符合條件的數組成員的位置,如果所有成員都不符合條件,則返回-1.
7、數組實例的entries(),keys()和values()
ES6提供三個新的方法——entries(), keys()和values()——用于遍歷數組。keys()是對鍵名的遍歷、values()是對鍵值的遍歷,entries()是對鍵值對的遍歷。
感覺可以用foreach一步做到,沒必要細看。。。。
8、數組實例的includes()
Array.prototype.includes方法返回一個布爾值,表示某個數組是否包含給定的值,與字符串的includes方法類似。ES2016引入了該方法。
[1, 2, 3].includes(2) // true [1, 2, 3].includes(4) // false [1, 2, NaN].includes(NaN) // true [1, 2, 3].includes(3, 3); // false 第二個參數表示搜索的起始位置 [1, 2, 3].includes(3, -1); //true
9、數組實例的flat(),flatMap()
數組的成員有時還是數組,Array.prototype.flat()用于將嵌套的數組“拉平”,變成一維的數組。該方法返回一個新數組,對原數據沒有影響。
[1, 2, [3, [4, 5]]].flat(); // [1, 2, 3, [4, 5]] 默認只會“拉平”一層 [1, 2, , [3, [4, 5]]].flat(2); // [1, 2, 3, 4, 5] 參數為2,表示要“拉平”兩層的嵌套數組,會跳過空位 [1, [2, [3]]].flat(Infinity); // [1, 2, 3] Infinity關鍵字作為參數,不管有多少層嵌套,都要轉成一維數組
flatMap()方法對原數組的每個成員執行一個函數(相當于執行Array.prototype.map()),然后回返回值組成的數組執行flat()方法(默認只能展開一層)。該方法返回一個新數組,不改變原數組。
[1, 2, 3, 4].flatMap(x => [[x * 2]]) // [[2], [4], [6], [8]] 相當于[[[2]], [[4]], [[6]], [[8]]].flat()
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/105574.html
摘要:在我們經常用到固定頭部和底部,自適應中間部分,或者固定左側,自適應右側等。在網上看了很多方法,一般都是通過絕對定位完成,具體可以網上去搜,這樣可以完成上中下的布局,但是這次基礎上再做左右布局浮動會出現問題,具體什么問題我沒有深究。 在css我們經常用到固定頭部和底部,自適應中間部分,或者固定左側,自適應右側等。在網上看了很多方法,一般都是通過絕對定位完成,position: absol...
摘要:基本布局上中左右下布局頭部左側超過高度出現滾動條超過高度出現滾動條超過高度出現滾動條超過高度出現滾動條超過高度出現滾動條超過高度出現滾動條超過高度出現滾動條超過高度出現滾動條超過高度出現滾動條超過高度出現滾動條超過高度出 基本布局1: 上中(左右)下布局 html,body{ margin:0; height:100%; ove...
摘要:基本布局上中左右下布局頭部左側超過高度出現滾動條超過高度出現滾動條超過高度出現滾動條超過高度出現滾動條超過高度出現滾動條超過高度出現滾動條超過高度出現滾動條超過高度出現滾動條超過高度出現滾動條超過高度出現滾動條超過高度出 基本布局1: 上中(左右)下布局 html,body{ margin:0; height:100%; ove...
摘要:代理模式的擴展普通代理這種代理就是客戶端只能訪問代理角色,而不能訪問真實角色。與設計模式之蟬代理模式上片基本差不多。 代理模式的擴展 1 普通代理 :這種代理就是客戶端只能訪問代理角色,而不能訪問真實角色。與設計模式之蟬——代理模式上 片基本差不多。(1)Subject抽象主題角色: showImg(https://segmentfault.com/img/bVbh8S5?w=1954...
摘要:本書屬于基礎類書籍,會有比較多的基礎知識,所以這里僅記錄平常不怎么容易注意到的知識點,不會全記,供大家和自己翻閱不錯,下冊的知識點就這么少,非常不推介看下冊上中下三本的讀書筆記你不知道的上讀書筆記你不知道的中讀書筆記你不知道的下讀書筆記第三 本書屬于基礎類書籍,會有比較多的基礎知識,所以這里僅記錄平常不怎么容易注意到的知識點,不會全記,供大家和自己翻閱; 不錯,下冊的知識點就這么少,非...
閱讀 3937·2021-10-12 10:12
閱讀 2897·2021-09-10 11:18
閱讀 3681·2019-08-30 15:54
閱讀 2814·2019-08-30 15:53
閱讀 645·2019-08-30 13:54
閱讀 976·2019-08-30 13:21
閱讀 2267·2019-08-30 12:57
閱讀 1698·2019-08-30 11:10