『ES6』ES6 - 学习笔记
比較 var 和 let 關(guān)鍵字的作用域
使用 var 關(guān)鍵字聲明變量時(shí),它是全局聲明的,如果在函數(shù)內(nèi)部聲明則是局部聲明的。
let 關(guān)鍵字的行為類似,但有一些額外的功能。 在代碼塊、語(yǔ)句或表達(dá)式中使用 let 關(guān)鍵字聲明變量時(shí),其作用域僅限于該代碼塊、語(yǔ)句或表達(dá)式。
例如:
var numArray = []; for (var i = 0; i < 3; i++) {numArray.push(i); } console.log(numArray); console.log(i);此處控制臺(tái)將顯示值 [0, 1, 2] 和 3。
使用 var 關(guān)鍵字,i 是全局聲明的。 所以當(dāng) i++ 被執(zhí)行時(shí),它會(huì)更新全局變量。 此代碼類似于以下內(nèi)容:
var numArray = []; var i; for (i = 0; i < 3; i++) {numArray.push(i); } console.log(numArray); console.log(i);此處控制臺(tái)將顯示值 [0, 1, 2] 和 3。
如果你創(chuàng)建一個(gè)函數(shù),將它存儲(chǔ)起來,稍后在使用 i 變量的 for 循環(huán)中使用。這么做可能會(huì)出現(xiàn)問題。 這是因?yàn)榇鎯?chǔ)的函數(shù)將始終引用更新后的全局 i 變量的值。
var printNumTwo; for (var i = 0; i < 3; i++) {if (i === 2) {printNumTwo = function() {return i;};} } console.log(printNumTwo());此處控制臺(tái)將顯示值 3。
可以看到,printNumTwo() 打印了 3 而不是 2。 這是因?yàn)橘x值給 i 的值已經(jīng)更新,printNumTwo() 返回全局的 i,而不是在 for 循環(huán)中創(chuàng)建函數(shù)時(shí) i 的值。 let 關(guān)鍵字就不會(huì)出現(xiàn)這種現(xiàn)象:
let printNumTwo; for (let i = 0; i < 3; i++) {if (i === 2) {printNumTwo = function() {return i;};} } console.log(printNumTwo()); console.log(i);在這里控制臺(tái)將顯示值 2 和一個(gè)錯(cuò)誤提示 i is not defined。
i 未定義,因?yàn)樗鼪]有在全局范圍內(nèi)聲明。 它只在 for 循環(huán)語(yǔ)句中被聲明。 printNumTwo() 返回了正確的值,因?yàn)?let 關(guān)鍵字創(chuàng)建了三個(gè)具有唯一值(0、1 和 2)的不同 i 變量在循環(huán)語(yǔ)句中。
Object.freeze 防止對(duì)象改變
const 聲明并不會(huì)真的保護(hù)數(shù)據(jù)不被改變。 為了確保數(shù)據(jù)不被改變,JavaScript 提供了一個(gè)函數(shù) Object.freeze。
任何更改對(duì)象的嘗試都將被拒絕,如果腳本在嚴(yán)格模式下運(yùn)行,將拋出錯(cuò)誤。
let obj = {name:"FreeCodeCamp",review:"Awesome" }; Object.freeze(obj); obj.review = "bad"; obj.name = "Test"; console.log(obj);obj.review 和 obj.newProp 賦值將導(dǎo)致錯(cuò)誤,因?yàn)槲覀兊木庉嬈髂J(rèn)在嚴(yán)格模式下運(yùn)行,控制臺(tái)將顯示值 { name: "FreeCodeCamp", review: "Awesome" }。
箭頭函數(shù)
在 JavaScript 和 TypeScript 里,我們會(huì)經(jīng)常遇到不需要給函數(shù)命名的情況,尤其是在需要將一個(gè)函數(shù)作為參數(shù)傳給另外一個(gè)函數(shù)的時(shí)候。 這時(shí),我們會(huì)創(chuàng)建 匿名函數(shù) 。 因?yàn)檫@些函數(shù)不會(huì)在其他地方復(fù)用,所以我們不需要給它們命名。
這種情況下,我們通常會(huì)使用以下語(yǔ)法:
const myFunc = function() {const myVar = "value";return myVar; }ES6 提供了其他寫匿名函數(shù)的方式的語(yǔ)法糖。 你可以使用 箭頭函數(shù) :
const myFunc = () => {const myVar = "value";return myVar; }當(dāng)不需要函數(shù)體,只返回一個(gè)值的時(shí)候 ,箭頭函數(shù)允許你省略 return 關(guān)鍵字和外面的大括號(hào)。 這樣就可以將一個(gè)簡(jiǎn)單的函數(shù)簡(jiǎn)化成一個(gè)單行語(yǔ)句。
const myFunc = () => "value";這段代碼默認(rèn)會(huì)返回字符串 value。
帶參數(shù)的箭頭函數(shù)
和一般的函數(shù)一樣,你也可以給箭頭函數(shù)傳遞參數(shù)。
JavaScript:
const doubler = (item) => item * 2; doubler(4);TypeScript:
const doubler = (item: number) => item * 2; doubler(4);doubler(4) 將返回 8。
如果箭頭函數(shù)只有一個(gè)參數(shù),則可以省略參數(shù)外面的括號(hào)。
const doubler = item => item * 2;注:在 TypeScript 里如果要進(jìn)行類型注解的話,是不可以省略括號(hào)的,如省略了括號(hào)的話,則不進(jìn)行類型注解,默認(rèn)為 any 類型
可以給箭頭函數(shù)傳遞多個(gè)參數(shù)。
JavaScript:
const multiplier = (item, multi) => item * multi; multiplier(4, 2);TypeScript:
const multiplier = (item: number, multi: number) => item * multi; multiplier(4, 2);multiplier(4, 2) 將返回 8。參數(shù)的箭頭函數(shù)
和一般的函數(shù)一樣,你也可以給箭頭函數(shù)傳遞參數(shù)。
const doubler = (item) => item * 2; doubler(4);doubler(4) 將返回 8。
如果箭頭函數(shù)只有一個(gè)參數(shù),則可以省略參數(shù)外面的括號(hào)。
const doubler = item => item * 2;可以給箭頭函數(shù)傳遞多個(gè)參數(shù)。
const multiplier = (item, multi) => item * multi; multiplier(4, 2);multiplier(4, 2) 將返回 8。
設(shè)置函數(shù)的默認(rèn)參數(shù)
ES6 里允許給函數(shù)傳入默認(rèn)參數(shù),來構(gòu)建更加靈活的函數(shù)。
請(qǐng)看以下代碼:
const greeting = (name = "Anonymous") => "Hello " + name;console.log(greeting("John")); console.log(greeting());控制臺(tái)將顯示字符串 Hello John 和 Hello Anonymous。
默認(rèn)參數(shù)會(huì)在參數(shù)沒有被指定(值為 undefined)的時(shí)候起作用。 在上面的例子中,參數(shù) name 會(huì)在沒有得到新的值的時(shí)候,默認(rèn)使用值 Anonymous。 你還可以給多個(gè)參數(shù)賦予默認(rèn)值。
rest 操作符
ES6 推出了用于函數(shù)參數(shù)的 rest 操作符幫助我們創(chuàng)建更加靈活的函數(shù)。 rest 操作符可以用于創(chuàng)建有一個(gè)變量來接受多個(gè)參數(shù)的函數(shù)。 這些參數(shù)被儲(chǔ)存在一個(gè)可以在函數(shù)內(nèi)部讀取的數(shù)組中。
請(qǐng)看以下代碼:
function howMany(...args) {return "You have passed " + args.length + " arguments."; } console.log(howMany(0, 1, 2)); console.log(howMany("string", null, [1, 2, 3], { }));控制臺(tái)將顯示字符串 You have passed 3 arguments. 和 You have passed 4 arguments.。
使用 rest 參數(shù),就不需要查看 args 數(shù)組,并且允許我們?cè)趨?shù)數(shù)組上使用 map()、filter() 和 reduce()。
舉例:
/**** @returns {*}* @param args*/ const sum = (...args) => {return args.reduce((a, b) => a + b, 0); }console.log(sum(0, 1, 2))spread 運(yùn)算符展開數(shù)組項(xiàng)
ES6 引入了展開操作符,可以展開數(shù)組以及需要多個(gè)參數(shù)或元素的表達(dá)式。
下面的 ES5 代碼使用了 apply() 來計(jì)算數(shù)組的最大值:
var arr = [6, 89, 3, 45]; var maximus = Math.max.apply(null, arr);maximus 的值為 89。
我們必須使用 Math.max.apply(null, arr),因?yàn)?Math.max(arr) 返回 NaN。 Math.max() 函數(shù)中需要傳入的是一系列由逗號(hào)分隔的參數(shù),而不是一個(gè)數(shù)組。 展開操作符可以提升代碼的可讀性,使代碼易于維護(hù)。
const arr = [6, 89, 3, 45]; const maximus = Math.max(...arr);maximus 的值應(yīng)該是 89。
...arr 返回一個(gè)解壓的數(shù)組。 也就是說,它展開數(shù)組。 然而,展開操作符只能夠在函數(shù)的參數(shù)中或者數(shù)組中使用。 下面的代碼將會(huì)報(bào)錯(cuò):
const spreaded = ...arr;使用解構(gòu)賦值來獲取對(duì)象的值
解構(gòu)賦值是 ES6 引入的新語(yǔ)法,用來從數(shù)組和對(duì)象中提取值,并優(yōu)雅地對(duì)變量進(jìn)行賦值。
有如下 ES5 代碼:
const user = { name: 'John Doe', age: 34 };const name = user.name; const age = user.age;name 的值應(yīng)該是字符串 John Doe, age 的值應(yīng)該是數(shù)字 34。
下面是使用 ES6 解構(gòu)賦值語(yǔ)句,實(shí)現(xiàn)相同效果:
const { name, age } = user;同樣,name 的值應(yīng)該是字符串 John Doe, age 的值應(yīng)該是數(shù)字 34。
在這里,自動(dòng)創(chuàng)建 name 和 age 變量,并將 user 對(duì)象相應(yīng)屬性的值賦值給它們。 這個(gè)方法簡(jiǎn)潔多了。
你可以從對(duì)象中提取盡可能多或很少的值。
使用解構(gòu)賦值從對(duì)象中分配變量
可以給解構(gòu)的值賦予一個(gè)新的變量名, 通過在賦值的時(shí)候?qū)⑿碌淖兞棵旁诿疤?hào)后面來實(shí)現(xiàn)。
還是以上個(gè)例子的對(duì)象來舉例:
const user = { name: 'John Doe', age: 34 };這是指定新的變量名的例子:
const { name: userName, age: userAge } = user;你可以這么理解這段代碼:獲取 user.name 的值,將它賦給一個(gè)新的變量 userName,等等。 userName 的值將是字符串 John Doe,userAge 的值將是數(shù)字 34。
使用解構(gòu)賦值從嵌套對(duì)象中分配變量
使用與前面的例子中類似的對(duì)象:
const user = {johnDoe: { age: 34,email: 'johnDoe@freeCodeCamp.com'} };這是解構(gòu)對(duì)象的屬性值賦值給具有相同名字的變量:
const { johnDoe: { age, email }} = user;這是將對(duì)象的屬性值賦值給具有不同名字的變量:
const { johnDoe: { age: userAge, email: userEmail }} = user;使用解構(gòu)賦值從數(shù)組中分配變量
在 ES6 里面,解構(gòu)數(shù)組可以如同解構(gòu)對(duì)象一樣簡(jiǎn)單。
與數(shù)組解構(gòu)不同,數(shù)組的擴(kuò)展運(yùn)算會(huì)將數(shù)組里的所有內(nèi)容分解成一個(gè)由逗號(hào)分隔的列表。 所以,你不能選擇哪個(gè)元素來給變量賦值。
而對(duì)數(shù)組進(jìn)行解構(gòu)卻可以讓我們做到這一點(diǎn):
const [a, b] = [1, 2, 3, 4, 5, 6]; console.log(a, b);控制臺(tái)將顯示 a 和 b 的值為 1, 2。
數(shù)組的第一個(gè)值被賦值給變量 a,數(shù)組的第二個(gè)值被賦值給變量 b。 我們甚至能在數(shù)組解構(gòu)中使用逗號(hào)分隔符,來獲取任意一個(gè)想要的值:
const [a, b,,, c] = [1, 2, 3, 4, 5, 6]; console.log(a, b, c);控制臺(tái)將顯示 a、b 和 c 的值為 1, 2, 5。
使用解構(gòu)賦值配合 rest 操作符來重新分配數(shù)組元素
在解構(gòu)數(shù)組的某些情況下,我們可能希望將剩下的元素放進(jìn)另一個(gè)數(shù)組里面。
以下代碼的結(jié)果與使用 Array.prototype.slice() 類似:
const [a, b, ...arr] = [1, 2, 3, 4, 5, 7]; console.log(a, b); console.log(arr);控制臺(tái)將顯示 1, 2 和 [3, 4, 5, 7]。
變量 a 和 b 分別接收數(shù)組的第一個(gè)和第二個(gè)值。 之后,因?yàn)?rest 操作符的存在,arr 獲取了原數(shù)組剩余的元素的值。 rest 操作符 只能對(duì)數(shù)組列表最后的元素起作用。 這意味著你不能使用 rest 操作符 來截取原數(shù)組中間的元素作為子數(shù)組。
使用解構(gòu)賦值將對(duì)象作為函數(shù)的參數(shù)傳遞
在某些情況下,你可以在函數(shù)的參數(shù)里直接解構(gòu)對(duì)象。
請(qǐng)看以下代碼:
const profileUpdate = (profileData) => {const { name, age, nationality, location } = profileData;}上面的操作解構(gòu)了傳給函數(shù)的對(duì)象。 這樣的操作也可以直接在參數(shù)里完成:
const profileUpdate = ({ name, age, nationality, location }) => {}當(dāng) profileData 被傳遞到上面的函數(shù)時(shí),從函數(shù)參數(shù)中解構(gòu)出值以在函數(shù)內(nèi)使用。
簡(jiǎn)單字段編寫簡(jiǎn)潔的對(duì)象字面量聲明
ES6 添加了一些很棒的功能,用于更方便地定義對(duì)象。
請(qǐng)看以下代碼:
const getMousePosition = (x, y) => ({x: x,y: y });getMousePosition 簡(jiǎn)單的函數(shù),返回?fù)碛袃蓚€(gè)屬性的對(duì)象。 ES6 提供了一個(gè)語(yǔ)法糖,消除了類似 x: x 這種冗余的寫法。 你可以只寫一次 x,解釋器會(huì)自動(dòng)將其轉(zhuǎn)換成 x: x(或效果相同的內(nèi)容)。 下面是使用這種語(yǔ)法重寫的同樣的函數(shù):
const getMousePosition = (x, y) => ({ x, y });ES6 編寫簡(jiǎn)潔的函數(shù)聲明
在 ES5 中,當(dāng)我們需要在對(duì)象中定義一個(gè)函數(shù)的時(shí)候,必須像這樣使用 function 關(guān)鍵字:
const person = {name: "Taylor",sayHello: function() {return `Hello! My name is ${this.name}.`;} };用 ES6 的語(yǔ)法在對(duì)象中定義函數(shù)的時(shí)候,可以刪除 function 關(guān)鍵詞和冒號(hào)。 請(qǐng)看以下例子:
const person = {name: "Taylor",sayHello() {return `Hello! My name is ${this.name}.`;} };使用 class 語(yǔ)法定義構(gòu)造函數(shù)
ES6 提供了一個(gè)新的創(chuàng)建對(duì)象的語(yǔ)法,使用關(guān)鍵字 class。
值得注意的是,class 只是一個(gè)語(yǔ)法糖,它并不像 Java、Python 或者 Ruby 這一類的語(yǔ)言一樣,嚴(yán)格履行了面向?qū)ο蟮拈_發(fā)規(guī)范。
在 ES5 里面,我們通常會(huì)定義一個(gè)構(gòu)造函數(shù) constructor,然后使用 new 關(guān)鍵字來實(shí)例化一個(gè)對(duì)象:
var SpaceShuttle = function(targetPlanet){this.targetPlanet = targetPlanet; } var zeus = new SpaceShuttle('Jupiter');class 語(yǔ)法只是簡(jiǎn)單地替換了構(gòu)造函數(shù) constructor 的寫法:
class SpaceShuttle {constructor(targetPlanet) {this.targetPlanet = targetPlanet;} } const zeus = new SpaceShuttle('Jupiter');應(yīng)該注意 class 關(guān)鍵字聲明了一個(gè)新的函數(shù),里面添加了一個(gè)構(gòu)造函數(shù)。 當(dāng)用 new 創(chuàng)建一個(gè)新的對(duì)象時(shí),構(gòu)造函數(shù)會(huì)被調(diào)用。
**注意:**首字母大寫駝峰命名法 UpperCamelCase 是 ES6 class 命名的慣例,就像上面的 SpaceShuttle。
constructor 方法是一個(gè)特殊方法,用于創(chuàng)建和初始化 class 創(chuàng)建的對(duì)象。
創(chuàng)建一個(gè)模塊腳本
起初,JavaScript 幾乎只在 HTML web 扮演一個(gè)很小的角色。 今天,一切不同了,很多網(wǎng)站幾乎全是用 JavaScript 所寫。 為了讓 JavaScript 更模塊化、更整潔以及更易于維護(hù),ES6 引入了在多個(gè) JavaScript 文件之間共享代碼的機(jī)制。 它可以導(dǎo)出文件的一部分供其它文件使用,然后在需要它的地方按需導(dǎo)入。 為了使用這一功能, 需要在 HTML 文檔里創(chuàng)建一個(gè) type 為 module 的腳本。 例子如下:
<script type="module" src="filename.js"></script>使用了 module 類型的腳本可以使用 import 和 export 特性
用 export default 創(chuàng)建一個(gè)默認(rèn)導(dǎo)出
在 export 的課程中,你學(xué)習(xí)了命名導(dǎo)出語(yǔ)法, 這可以在其他文件中引用一些函數(shù)或者變量。
還需要了解另外一種被稱為默認(rèn)導(dǎo)出的 export 的語(yǔ)法。 在文件中只有一個(gè)值需要導(dǎo)出的時(shí)候,通常會(huì)使用這種語(yǔ)法。 它也常常用于給文件或者模塊創(chuàng)建返回值。
下面是使用 export default 的例子:
export default function add(x, y) {return x + y; }export default function(x, y) {return x + y; }第一個(gè)是命名函數(shù),第二個(gè)是匿名函數(shù)。
export default 用于為模塊或文件聲明一個(gè)返回值,在每個(gè)文件或者模塊中應(yīng)當(dāng)只默認(rèn)導(dǎo)出一個(gè)值。 此外,你不能將 export default 與 var、let 或 const 同時(shí)使用。
Promise
創(chuàng)建一個(gè) JavaScript Promise
Promise 是異步編程的一種解決方案 - 它在未來的某時(shí)會(huì)生成一個(gè)值。 任務(wù)完成,分執(zhí)行成功和執(zhí)行失敗兩種情況。 Promise 是構(gòu)造器函數(shù),需要通過 new 關(guān)鍵字來創(chuàng)建。 構(gòu)造器參數(shù)是一個(gè)函數(shù),該函數(shù)有兩個(gè)參數(shù) - resolve 和 reject。 通過它們來判斷 promise 的執(zhí)行結(jié)果。 用法如下:
const myPromise = new Promise((resolve, reject) => {});通過 resolve 和 reject 完成 Promise
Promise 有三個(gè)狀態(tài):pending、fulfilled 和 rejected。 上一個(gè)挑戰(zhàn)里創(chuàng)建的 promise 一直阻塞在 pending 狀態(tài)里,因?yàn)闆]有調(diào)用 promise 的完成方法。 Promise 提供的 resolve 和 reject 參數(shù)就是用來結(jié)束 promise 的。 Promise 成功時(shí)調(diào)用 resolve,promise 執(zhí)行失敗時(shí)調(diào)用 reject, 如下文所述,這些方法需要有一個(gè)參數(shù)。
const myPromise = new Promise((resolve, reject) => {if(condition here) {resolve("Promise was fulfilled");} else {reject("Promise was rejected");} });上面的示例使用字符串作為這些函數(shù)的參數(shù),但參數(shù)實(shí)際上可以是任何格式。 通常,它可能是一個(gè)包含數(shù)據(jù)的對(duì)象,你可以將它放在網(wǎng)站或其他地方。
用 then 處理 Promise 完成的情況
當(dāng)程序需要花費(fèi)未知的時(shí)間才能完成時(shí)(比如一些異步操作),一般是服務(wù)器請(qǐng)求,promise 很有用。 服務(wù)器請(qǐng)求會(huì)花費(fèi)一些時(shí)間,當(dāng)結(jié)束時(shí),需要根據(jù)服務(wù)器的響應(yīng)執(zhí)行一些操作。 這可以用 then 方法來實(shí)現(xiàn), 當(dāng) promise 完成 resolve 時(shí)會(huì)觸發(fā) then 方法。 例子如下:
myPromise.then(result => {});result 即傳入 resolve 方法的參數(shù)。
使用 catch 處理 Promise 失敗的情況
當(dāng) promise 失敗時(shí)會(huì)調(diào)用 catch 方法。 當(dāng) promise 的 reject 方法執(zhí)行時(shí)會(huì)直接調(diào)用。 用法如下:
myPromise.catch(error => {});error 是傳入 reject 方法的參數(shù)。
總結(jié)
以上是生活随笔為你收集整理的『ES6』ES6 - 学习笔记的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【Sass】全面的 Sass 教程及学习
- 下一篇: 【Py面试题】找到数组或整数列表中连续子