ES6新特性
ES6語法
Tags: javascript
[TOC]
const 與 let 變量
使用var帶來的麻煩:
function getClothing(isCold) {if (isCold) {var freezing = 'Grab a jacket!';} else {var hot = 'It's a shorts kind of day.';console.log(freezing);} }運行getClothing(false)后輸出的是undefined,這是因為執行function函數之前,所有變量都會被提升, 提升到函數作用域頂部.
let與const聲明的變量解決了這種問題,因為他們是塊級作用域, 在代碼塊(用{}表示)中使用let或const聲明變量, 該變量會陷入暫時性死區直到該變量的聲明被處理.
function getClothing(isCold) {if (isCold) {const freezing = 'Grab a jacket!';} else {const hot = 'It's a shorts kind of day.';console.log(freezing);} }運行getClothing(false)后輸出的是ReferenceError: freezing is not defined,因為 freezing 沒有在 else 語句、函數作用域或全局作用域內聲明,所以拋出 ReferenceError。
關于使用let與const規則:
- 使用let聲明的變量可以重新賦值,但是不能在同一作用域內重新聲明
- 使用const聲明的變量必須賦值初始化,但是不能在同一作用域類重新聲明也無法重新賦值.
模板字面量
在ES6之前,將字符串連接到一起的方法是+或者concat()方法,如
const student = {name: 'Richard Kalehoff',guardian: 'Mr. Kalehoff' };const teacher = {name: 'Mrs. Wilson',room: 'N231' }let message = student.name + ' please see ' + teacher.name + ' in ' + teacher.room + ' to pick up your report card.';模板字面量本質上是包含嵌入式表達式的字符串字面量.
模板字面量用倒引號 ( `` )(而不是單引號 ( '' ) 或雙引號( "" ))表示,可以包含用 ${expression} 表示的占位符
解構
在ES6中,可以使用解構從數組和對象提取值并賦值給獨特的變量
解構數組的值:
const point = [10, 25, -34]; const [x, y, z] = point; console.log(x, y, z);Prints: 10 25 -34
[]表示被解構的數組, x,y,z表示要將數組中的值存儲在其中的變量, 在解構數組是, 還可以忽略值, 例如const[x,,z]=point,忽略y坐標.
解構對象中的值:
const gemstone = {type: 'quartz',color: 'rose',karat: 21.29 }; const {type, color, karat} = gemstone; console.log(type, color, karat);花括號 { } 表示被解構的對象,type、color 和 karat 表示要將對象中的屬性存儲到其中的變量
對象字面量簡寫法
let type = 'quartz'; let color = 'rose'; let carat = 21.29;const gemstone = {type: type,color: color,carat: carat };console.log(gemstone);使用和所分配的變量名稱相同的名稱初始化對象時如果屬性名稱和所分配的變量名稱一樣,那么就可以從對象屬性中刪掉這些重復的變量名稱。
let type = 'quartz'; let color = 'rose'; let carat = 21.29; const gemstone = {type,color,carat}; console.log(gemstone);簡寫方法的名稱:
const gemstone = {type,color,carat,calculateWorth: function() {// 將根據類型(type),顏色(color)和克拉(carat)計算寶石(gemstone)的價值} };匿名函數被分配給屬性 calculateWorth,但是真的需要 function 關鍵字嗎?在 ES6 中不需要!
let gemstone = {type,color,carat,calculateWorth() { ... } };for...of循環
for...of循環是最新添加到 JavaScript 循環系列中的循環。
它結合了其兄弟循環形式 for 循環和 for...in 循環的優勢,可以循環任何可迭代(也就是遵守可迭代協議)類型的數據。默認情況下,包含以下數據類型:String、Array、Map 和 Set,注意不包含 Object 數據類型(即 {})。默認情況下,對象不可迭代。
for循環
const digits = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; for (let i = 0; i < digits.length; i++) {console.log(digits[i]); }for 循環的最大缺點是需要跟蹤計數器和退出條件。
雖然 for 循環在循環數組時的確具有優勢,但是某些數據結構不是數組,因此并非始終適合使用 loop 循環。
for...in循環
const digits = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];for (const index in digits) {console.log(digits[index]); }依然需要使用 index 來訪問數組的值
當你需要向數組中添加額外的方法(或另一個對象)時,for...in 循環會帶來很大的麻煩。因為 for...in 循環循環訪問所有可枚舉的屬性,意味著如果向數組的原型中添加任何其他屬性,這些屬性也會出現在循環中。
forEach 循環 是另一種形式的 JavaScript 循環。但是,forEach() 實際上是數組方法,因此只能用在數組中。也無法停止或退出 forEach 循環。如果希望你的循環中出現這種行為,則需要使用基本的 for 循環。
for...of循環
for...of 循環用于循環訪問任何可迭代的數據類型。
for...of 循環的編寫方式和 for...in 循環的基本一樣,只是將 in 替換為 of,可以忽略索引。
建議使用復數對象名稱來表示多個值的集合。這樣,循環該集合時,可以使用名稱的單數版本來表示集合中的單個值。例如,for (const button of buttons) {…}。
for...of 循環還具有其他優勢,解決了 for 和 for...in 循環的不足之處。你可以隨時停止或退出 for...of 循環。
for (const digit of digits) {if (digit % 2 === 0) {continue;}console.log(digit); }不用擔心向對象中添加新的屬性。for...of 循環將只循環訪問對象中的值。
Array.prototype.decimalfy = function() {for (i = 0; i < this.length; i++) {this[i] = this[i].toFixed(2);} };const digits = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];for (const digit of digits) {console.log(digit); }展開運算符
展開運算符(用三個連續的點 (...) 表示)是 ES6 中的新概念,使你能夠將字面量對象展開為多個元素
const books = ["Don Quixote", "The Hobbit", "Alice in Wonderland", "Tale of Two Cities"]; console.log(...books);Prints: Don Quixote The Hobbit Alice in Wonderland Tale of Two Cities
展開運算符的一個用途是結合數組。
如果你需要結合多個數組,在有展開運算符之前,必須使用 Array的 concat() 方法。
const fruits = ["apples", "bananas", "pears"]; const vegetables = ["corn", "potatoes", "carrots"]; const produce = fruits.concat(vegetables); console.log(produce);Prints: ["apples", "bananas", "pears", "corn", "potatoes", "carrots"]
使用展開符來結合數組
const fruits = ["apples", "bananas", "pears"]; const vegetables = ["corn", "potatoes", "carrots"]; const produce = [...fruits,...vegetables]; console.log(produce);剩余參數(可變參數)
使用展開運算符將數組展開為多個元素, 使用剩余參數可以將多個元素綁定到一個數組中.
剩余參數也用三個連續的點 ( ... ) 表示,使你能夠將不定數量的元素表示為數組.
用途1: 將變量賦數組值時:
const order = [20.17, 18.67, 1.50, "cheese", "eggs", "milk", "bread"]; const [total, subtotal, tax, ...items] = order; console.log(total, subtotal, tax, items);用途2: 可變參數函數
對于參數不固定的函數,ES6之前是使用參數對象(arguments)處理:
在ES6中使用剩余參數運算符則更為簡潔,可讀性提高:
function sum(...nums) {let total = 0; for(const num of nums) {total += num;}return total; }ES6箭頭函數
ES6之前,使用普通函數把其中每個名字轉換為大寫形式:
const upperizedNames = ['Farrin', 'Kagure', 'Asser'].map(function(name) { return name.toUpperCase(); });箭頭函數表示:
const upperizedNames = ['Farrin', 'Kagure', 'Asser'].map(name => name.toUpperCase() );普通函數可以是函數聲明或者函數表達式, 但是箭頭函數始終都是表達式, 全程是箭頭函數表達式, 因此因此僅在表達式有效時才能使用,包括:
- 存儲在變量中,
- 當做參數傳遞給函數,
- 存儲在對象的屬性中。
可以如下調用:
greet('Asser');如果函數的參數只有一個,不需要使用()包起來,但是只有一個或者多個, 則必須需要將參數列表放在圓括號內:
// 空參數列表需要括號 const sayHi = () => console.log('Hello Udacity Student!');// 多個參數需要括號 const orderIceCream = (flavor, cone) => console.log(`Here's your ${flavor} ice cream in a ${cone} cone.`); orderIceCream('chocolate', 'waffle');一般箭頭函數都只有一個表達式作為函數主題:
const upperizedNames = ['Farrin', 'Kagure', 'Asser'].map(name => name.toUpperCase() );這種函數表達式形式稱為簡寫主體語法:
- 在函數主體周圍沒有花括號,
- 自動返回表達式
但是如果箭頭函數的主體內需要多行代碼, 則需要使用常規主體語法:
- 它將函數主體放在花括號內
- 需要使用 return 語句來返回內容。
javascript標準函數this
sundae這個構造函數內的this的值是實例對象, 因為他使用new被調用.
函數使用call/apply被調用,this的值指向指定的obj2,因為call()第一個參數明確設置this的指向
函數是對象的方法, this指向就是那個對象,此處this就是指向data.
此處是this指向全局對象,在嚴格模式下,指向undefined.
javascript中this是很復雜的概念, 要詳細判斷this,請參考this豁然開朗
箭頭函數和this
對于普通函數, this的值基于函數如何被調用, 對于箭頭函數,this的值基于函數周圍的上下文, 換句話說,this的值和函數外面的this的值是一樣的.
function IceCream() {this.scoops = 0; }// 為 IceCream 添加 addScoop 方法 IceCream.prototype.addScoop = function() {setTimeout(function() {this.scoops++;console.log('scoop added!');console.log(this.scoops); // undefined+1=NaNconsole.log(dessert.scoops); //0}, 500); };----------標題const dessert = new IceCream(); dessert.addScoop();傳遞給 setTimeout() 的函數被調用時沒用到 new、call() 或 apply(),也沒用到上下文對象。意味著函數內的 this 的值是全局對象,不是 dessert 對象。實際上發生的情況是,創建了新的 scoops 變量(默認值為 undefined),然后遞增(undefined + 1 結果為 NaN);
解決此問題的方式之一是使用閉包(closure):
// 構造函數 function IceCream() {this.scoops = 0; }// 為 IceCream 添加 addScoop 方法 IceCream.prototype.addScoop = function() {const cone = this; // 設置 `this` 給 `cone`變量setTimeout(function() {cone.scoops++; // 引用`cone`變量console.log('scoop added!'); console.log(dessert.scoops);//1}, 0.5); };const dessert = new IceCream(); dessert.addScoop();箭頭函數的作用正是如此, 將setTimeOut()的函數改為剪頭函數:
// 構造函數 function IceCream() {this.scoops = 0; }// 為 IceCream 添加 addScoop 方法 IceCream.prototype.addScoop = function() {setTimeout(() => { // 一個箭頭函數被傳遞給setTimeoutthis.scoops++;console.log('scoop added!');console.log(dessert.scoops);//1}, 0.5); };const dessert = new IceCream(); dessert.addScoop();默認參數函數
function greet(name, greeting) {name = (typeof name !== 'undefined') ? name : 'Student';greeting = (typeof greeting !== 'undefined') ? greeting : 'Welcome';return `${greeting} ${name}!`; }greet(); // Welcome Student! greet('James'); // Welcome James! greet('Richard', 'Howdy'); // Howdy Richard!greet() 函數中混亂的前兩行的作用是什么?它們的作用是當所需的參數未提供時,為函數提供默認的值。但是看起來很麻煩, ES6引入一種新的方式創建默認值, 他叫默認函數參數:
function greet(name = 'Student', greeting = 'Welcome') {return `${greeting} ${name}!`; }greet(); // Welcome Student! greet('James'); // Welcome James! greet('Richard', 'Howdy'); // Howdy Richard!默認值與解構
createGrid() 函數預期傳入的是數組。它通過解構將數組中的第一項設為 width,第二項設為 height。如果數組為空,或者只有一項,那么就會使用默認參數,并將缺失的參數設為默認值 5。
但是存在一個問題:
createGrid(); // throws an errorUncaught TypeError: Cannot read property 'Symbol(Symbol.iterator)' of undefined
出現錯誤,因為 createGrid() 預期傳入的是數組,然后對其進行解構。因為函數被調用時沒有傳入數組,所以出現問題。但是,我們可以使用默認的函數參數!
function createGrid([width = 5, height = 5] = []) {return `Generating a grid of ${width} by ${height}`; } createGrid(); // Generates a 5 x 5 gridReturns: Generates a 5 x 5 grid
就像使用數組默認值解構數組一樣,函數可以讓對象成為一個默認參數,并使用對象解構:
function createSundae({scoops = 1, toppings = ['Hot Fudge']}={}) {const scoopText = scoops === 1 ? 'scoop' : 'scoops';return `Your sundae has ${scoops} ${scoopText} with ${toppings.join(' and ')} toppings.`; }createSundae({}); // Your sundae has 1 scoop with Hot Fudge toppings. createSundae({scoops: 2}); // Your sundae has 2 scoops with Hot Fudge toppings. createSundae({scoops: 2, toppings: ['Sprinkles']}); // Your sundae has 2 scoops with Sprinkles toppings. createSundae({toppings: ['Cookie Dough']}); // Your sundae has 1 scoop with Cookie Dough toppings. createSundae(); // Your sundae has 1 scoop with Hot Fudge toppings.默認函數參數只是個簡單的添加內容,但是卻帶來很多便利!與數組默認值相比,對象默認值具備的一個優勢是能夠處理跳過的選項。看看下面的代碼:
function createSundae({scoops = 1, toppings = ['Hot Fudge']} = {}) { … }在 createSundae() 函數使用對象默認值進行解構時,如果你想使用 scoops 的默認值,但是更改 toppings,那么只需使用 toppings 傳入一個對象:
createSundae({toppings: ['Hot Fudge', 'Sprinkles', 'Caramel']});將上述示例與使用數組默認值進行解構的同一函數相對比。
function createSundae([scoops = 1, toppings = ['Hot Fudge']] = []) { … }對于這個函數,如果想使用 scoops 的默認數量,但是更改 toppings,則必須以這種奇怪的方式調用你的函數:
createSundae([undefined, ['Hot Fudge', 'Sprinkles', 'Caramel']]);因為數組是基于位置的,我們需要傳入 undefined 以跳過第一個參數(并使用默認值)來到達第二個參數。
Javascript類
ES5創建類:
function Plane(numEngines) {this.numEngines = numEngines;this.enginesActive = false; }// 由所有實例 "繼承" 的方法 Plane.prototype.startEngines = function () {console.log('starting engines...');this.enginesActive = true; };ES6類只是一個語法糖,原型繼續實際上在底層隱藏起來, 與傳統類機制語言有些區別.
class Plane {//constructor方法雖然在類中,但不是原型上的方法,只是用來生成實例的.constructor(numEngines) {this.numEngines = numEngines;this.enginesActive = false;}//原型上的方法, 由所有實例對象共享.startEngines() {console.log('starting engines…');this.enginesActive = true;} }console.log(typeof Plane); //functionjavascript中類其實只是function, 方法之間不能使用,,不用逗號區分屬性和方法.
靜態方法
要添加靜態方法,請在方法名稱前面加上關鍵字 static
- 關鍵字class帶來其他基于類的語言的很多思想,但是沒有向javascript中添加此功能
- javascript類實際上還是原型繼承
- 創建javascript類的新實例時必須使用new關鍵字
super 和 extends
使用新的super和extends關鍵字擴展類:
class Tree {constructor(size = '10', leaves = {spring: 'green', summer: 'green', fall: 'orange', winter: null}) {this.size = size;this.leaves = leaves;this.leafColor = null;}changeSeason(season) {this.leafColor = this.leaves[season];if (season === 'spring') {this.size += 1;}} }class Maple extends Tree {constructor(syrupQty = 15, size, leaves) {super(size, leaves); //super用作函數this.syrupQty = syrupQty;}changeSeason(season) {super.changeSeason(season);//super用作對象if (season === 'spring') {this.syrupQty += 1;}}gatherSyrup() {this.syrupQty -= 3;} }使用ES5編寫同樣功能的類:
function Tree(size, leaves) {this.size = size || 10;this.leaves = leaves || {spring: 'green', summer: 'green', fall: 'orange', winter: null};this.leafColor; }Tree.prototype.changeSeason = function(season) {this.leafColor = this.leaves[season];if (season === 'spring') {this.size += 1;} }function Maple (syrupQty, size, leaves) {Tree.call(this, size, leaves);this.syrupQty = syrupQty || 15; }Maple.prototype = Object.create(Tree.prototype); Maple.prototype.constructor = Maple;Maple.prototype.changeSeason = function(season) {Tree.prototype.changeSeason.call(this, season);if (season === 'spring') {this.syrupQty += 1;} }Maple.prototype.gatherSyrup = function() {this.syrupQty -= 3; }super 必須在 this 之前被調用
在子類構造函數中,在使用 this 之前,必須先調用超級類。
class Apple {} class GrannySmith extends Apple {constructor(tartnessLevel, energy) {this.tartnessLevel = tartnessLevel; // 在 'super' 之前會拋出一個錯誤!super(energy); } }ES6語法
Tags: javascript
[TOC]
const 與 let 變量
使用var帶來的麻煩:
function getClothing(isCold) {if (isCold) {var freezing = 'Grab a jacket!';} else {var hot = 'It's a shorts kind of day.';console.log(freezing);} }運行getClothing(false)后輸出的是undefined,這是因為執行function函數之前,所有變量都會被提升, 提升到函數作用域頂部.
let與const聲明的變量解決了這種問題,因為他們是塊級作用域, 在代碼塊(用{}表示)中使用let或const聲明變量, 該變量會陷入暫時性死區直到該變量的聲明被處理.
function getClothing(isCold) {if (isCold) {const freezing = 'Grab a jacket!';} else {const hot = 'It's a shorts kind of day.';console.log(freezing);} }運行getClothing(false)后輸出的是ReferenceError: freezing is not defined,因為 freezing 沒有在 else 語句、函數作用域或全局作用域內聲明,所以拋出 ReferenceError。
關于使用let與const規則:
- 使用let聲明的變量可以重新賦值,但是不能在同一作用域內重新聲明
- 使用const聲明的變量必須賦值初始化,但是不能在同一作用域類重新聲明也無法重新賦值.
模板字面量
在ES6之前,將字符串連接到一起的方法是+或者concat()方法,如
const student = {name: 'Richard Kalehoff',guardian: 'Mr. Kalehoff' };const teacher = {name: 'Mrs. Wilson',room: 'N231' }let message = student.name + ' please see ' + teacher.name + ' in ' + teacher.room + ' to pick up your report card.';模板字面量本質上是包含嵌入式表達式的字符串字面量.
模板字面量用倒引號 ( `` )(而不是單引號 ( '' ) 或雙引號( "" ))表示,可以包含用 ${expression} 表示的占位符
解構
在ES6中,可以使用解構從數組和對象提取值并賦值給獨特的變量
解構數組的值:
const point = [10, 25, -34]; const [x, y, z] = point; console.log(x, y, z);Prints: 10 25 -34
[]表示被解構的數組, x,y,z表示要將數組中的值存儲在其中的變量, 在解構數組是, 還可以忽略值, 例如const[x,,z]=point,忽略y坐標.
解構對象中的值:
const gemstone = {type: 'quartz',color: 'rose',karat: 21.29 }; const {type, color, karat} = gemstone; console.log(type, color, karat);花括號 { } 表示被解構的對象,type、color 和 karat 表示要將對象中的屬性存儲到其中的變量
對象字面量簡寫法
let type = 'quartz'; let color = 'rose'; let carat = 21.29;const gemstone = {type: type,color: color,carat: carat };console.log(gemstone);使用和所分配的變量名稱相同的名稱初始化對象時如果屬性名稱和所分配的變量名稱一樣,那么就可以從對象屬性中刪掉這些重復的變量名稱。
let type = 'quartz'; let color = 'rose'; let carat = 21.29; const gemstone = {type,color,carat}; console.log(gemstone);簡寫方法的名稱:
const gemstone = {type,color,carat,calculateWorth: function() {// 將根據類型(type),顏色(color)和克拉(carat)計算寶石(gemstone)的價值} };匿名函數被分配給屬性 calculateWorth,但是真的需要 function 關鍵字嗎?在 ES6 中不需要!
let gemstone = {type,color,carat,calculateWorth() { ... } };for...of循環
for...of循環是最新添加到 JavaScript 循環系列中的循環。
它結合了其兄弟循環形式 for 循環和 for...in 循環的優勢,可以循環任何可迭代(也就是遵守可迭代協議)類型的數據。默認情況下,包含以下數據類型:String、Array、Map 和 Set,注意不包含 Object 數據類型(即 {})。默認情況下,對象不可迭代。
for循環
const digits = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; for (let i = 0; i < digits.length; i++) {console.log(digits[i]); }for 循環的最大缺點是需要跟蹤計數器和退出條件。
雖然 for 循環在循環數組時的確具有優勢,但是某些數據結構不是數組,因此并非始終適合使用 loop 循環。
for...in循環
const digits = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];for (const index in digits) {console.log(digits[index]); }依然需要使用 index 來訪問數組的值
當你需要向數組中添加額外的方法(或另一個對象)時,for...in 循環會帶來很大的麻煩。因為 for...in 循環循環訪問所有可枚舉的屬性,意味著如果向數組的原型中添加任何其他屬性,這些屬性也會出現在循環中。
forEach 循環 是另一種形式的 JavaScript 循環。但是,forEach() 實際上是數組方法,因此只能用在數組中。也無法停止或退出 forEach 循環。如果希望你的循環中出現這種行為,則需要使用基本的 for 循環。
for...of循環
for...of 循環用于循環訪問任何可迭代的數據類型。
for...of 循環的編寫方式和 for...in 循環的基本一樣,只是將 in 替換為 of,可以忽略索引。
建議使用復數對象名稱來表示多個值的集合。這樣,循環該集合時,可以使用名稱的單數版本來表示集合中的單個值。例如,for (const button of buttons) {…}。
for...of 循環還具有其他優勢,解決了 for 和 for...in 循環的不足之處。你可以隨時停止或退出 for...of 循環。
for (const digit of digits) {if (digit % 2 === 0) {continue;}console.log(digit); }不用擔心向對象中添加新的屬性。for...of 循環將只循環訪問對象中的值。
Array.prototype.decimalfy = function() {for (i = 0; i < this.length; i++) {this[i] = this[i].toFixed(2);} };const digits = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];for (const digit of digits) {console.log(digit); }展開運算符
展開運算符(用三個連續的點 (...) 表示)是 ES6 中的新概念,使你能夠將字面量對象展開為多個元素
const books = ["Don Quixote", "The Hobbit", "Alice in Wonderland", "Tale of Two Cities"]; console.log(...books);Prints: Don Quixote The Hobbit Alice in Wonderland Tale of Two Cities
展開運算符的一個用途是結合數組。
如果你需要結合多個數組,在有展開運算符之前,必須使用 Array的 concat() 方法。
const fruits = ["apples", "bananas", "pears"]; const vegetables = ["corn", "potatoes", "carrots"]; const produce = fruits.concat(vegetables); console.log(produce);Prints: ["apples", "bananas", "pears", "corn", "potatoes", "carrots"]
使用展開符來結合數組
const fruits = ["apples", "bananas", "pears"]; const vegetables = ["corn", "potatoes", "carrots"]; const produce = [...fruits,...vegetables]; console.log(produce);剩余參數(可變參數)
使用展開運算符將數組展開為多個元素, 使用剩余參數可以將多個元素綁定到一個數組中.
剩余參數也用三個連續的點 ( ... ) 表示,使你能夠將不定數量的元素表示為數組.
用途1: 將變量賦數組值時:
const order = [20.17, 18.67, 1.50, "cheese", "eggs", "milk", "bread"]; const [total, subtotal, tax, ...items] = order; console.log(total, subtotal, tax, items);用途2: 可變參數函數
對于參數不固定的函數,ES6之前是使用參數對象(arguments)處理:
在ES6中使用剩余參數運算符則更為簡潔,可讀性提高:
function sum(...nums) {let total = 0; for(const num of nums) {total += num;}return total; }ES6箭頭函數
ES6之前,使用普通函數把其中每個名字轉換為大寫形式:
const upperizedNames = ['Farrin', 'Kagure', 'Asser'].map(function(name) { return name.toUpperCase(); });箭頭函數表示:
const upperizedNames = ['Farrin', 'Kagure', 'Asser'].map(name => name.toUpperCase() );普通函數可以是函數聲明或者函數表達式, 但是箭頭函數始終都是表達式, 全程是箭頭函數表達式, 因此因此僅在表達式有效時才能使用,包括:
- 存儲在變量中,
- 當做參數傳遞給函數,
- 存儲在對象的屬性中。
可以如下調用:
greet('Asser');如果函數的參數只有一個,不需要使用()包起來,但是只有一個或者多個, 則必須需要將參數列表放在圓括號內:
// 空參數列表需要括號 const sayHi = () => console.log('Hello Udacity Student!');// 多個參數需要括號 const orderIceCream = (flavor, cone) => console.log(`Here's your ${flavor} ice cream in a ${cone} cone.`); orderIceCream('chocolate', 'waffle');一般箭頭函數都只有一個表達式作為函數主題:
const upperizedNames = ['Farrin', 'Kagure', 'Asser'].map(name => name.toUpperCase() );這種函數表達式形式稱為簡寫主體語法:
- 在函數主體周圍沒有花括號,
- 自動返回表達式
但是如果箭頭函數的主體內需要多行代碼, 則需要使用常規主體語法:
- 它將函數主體放在花括號內
- 需要使用 return 語句來返回內容。
javascript標準函數this
sundae這個構造函數內的this的值是實例對象, 因為他使用new被調用.
函數使用call/apply被調用,this的值指向指定的obj2,因為call()第一個參數明確設置this的指向
函數是對象的方法, this指向就是那個對象,此處this就是指向data.
此處是this指向全局對象,在嚴格模式下,指向undefined.
javascript中this是很復雜的概念, 要詳細判斷this,請參考this豁然開朗
箭頭函數和this
對于普通函數, this的值基于函數如何被調用, 對于箭頭函數,this的值基于函數周圍的上下文, 換句話說,this的值和函數外面的this的值是一樣的.
function IceCream() {this.scoops = 0; }// 為 IceCream 添加 addScoop 方法 IceCream.prototype.addScoop = function() {setTimeout(function() {this.scoops++;console.log('scoop added!');console.log(this.scoops); // undefined+1=NaNconsole.log(dessert.scoops); //0}, 500); };----------標題const dessert = new IceCream(); dessert.addScoop();傳遞給 setTimeout() 的函數被調用時沒用到 new、call() 或 apply(),也沒用到上下文對象。意味著函數內的 this 的值是全局對象,不是 dessert 對象。實際上發生的情況是,創建了新的 scoops 變量(默認值為 undefined),然后遞增(undefined + 1 結果為 NaN);
解決此問題的方式之一是使用閉包(closure):
// 構造函數 function IceCream() {this.scoops = 0; }// 為 IceCream 添加 addScoop 方法 IceCream.prototype.addScoop = function() {const cone = this; // 設置 `this` 給 `cone`變量setTimeout(function() {cone.scoops++; // 引用`cone`變量console.log('scoop added!'); console.log(dessert.scoops);//1}, 0.5); };const dessert = new IceCream(); dessert.addScoop();箭頭函數的作用正是如此, 將setTimeOut()的函數改為剪頭函數:
// 構造函數 function IceCream() {this.scoops = 0; }// 為 IceCream 添加 addScoop 方法 IceCream.prototype.addScoop = function() {setTimeout(() => { // 一個箭頭函數被傳遞給setTimeoutthis.scoops++;console.log('scoop added!');console.log(dessert.scoops);//1}, 0.5); };const dessert = new IceCream(); dessert.addScoop();默認參數函數
function greet(name, greeting) {name = (typeof name !== 'undefined') ? name : 'Student';greeting = (typeof greeting !== 'undefined') ? greeting : 'Welcome';return `${greeting} ${name}!`; }greet(); // Welcome Student! greet('James'); // Welcome James! greet('Richard', 'Howdy'); // Howdy Richard!greet() 函數中混亂的前兩行的作用是什么?它們的作用是當所需的參數未提供時,為函數提供默認的值。但是看起來很麻煩, ES6引入一種新的方式創建默認值, 他叫默認函數參數:
function greet(name = 'Student', greeting = 'Welcome') {return `${greeting} ${name}!`; }greet(); // Welcome Student! greet('James'); // Welcome James! greet('Richard', 'Howdy'); // Howdy Richard!默認值與解構
createGrid() 函數預期傳入的是數組。它通過解構將數組中的第一項設為 width,第二項設為 height。如果數組為空,或者只有一項,那么就會使用默認參數,并將缺失的參數設為默認值 5。
但是存在一個問題:
createGrid(); // throws an errorUncaught TypeError: Cannot read property 'Symbol(Symbol.iterator)' of undefined
出現錯誤,因為 createGrid() 預期傳入的是數組,然后對其進行解構。因為函數被調用時沒有傳入數組,所以出現問題。但是,我們可以使用默認的函數參數!
function createGrid([width = 5, height = 5] = []) {return `Generating a grid of ${width} by ${height}`; } createGrid(); // Generates a 5 x 5 gridReturns: Generates a 5 x 5 grid
就像使用數組默認值解構數組一樣,函數可以讓對象成為一個默認參數,并使用對象解構:
function createSundae({scoops = 1, toppings = ['Hot Fudge']}={}) {const scoopText = scoops === 1 ? 'scoop' : 'scoops';return `Your sundae has ${scoops} ${scoopText} with ${toppings.join(' and ')} toppings.`; }createSundae({}); // Your sundae has 1 scoop with Hot Fudge toppings. createSundae({scoops: 2}); // Your sundae has 2 scoops with Hot Fudge toppings. createSundae({scoops: 2, toppings: ['Sprinkles']}); // Your sundae has 2 scoops with Sprinkles toppings. createSundae({toppings: ['Cookie Dough']}); // Your sundae has 1 scoop with Cookie Dough toppings. createSundae(); // Your sundae has 1 scoop with Hot Fudge toppings.默認函數參數只是個簡單的添加內容,但是卻帶來很多便利!與數組默認值相比,對象默認值具備的一個優勢是能夠處理跳過的選項。看看下面的代碼:
function createSundae({scoops = 1, toppings = ['Hot Fudge']} = {}) { … }在 createSundae() 函數使用對象默認值進行解構時,如果你想使用 scoops 的默認值,但是更改 toppings,那么只需使用 toppings 傳入一個對象:
createSundae({toppings: ['Hot Fudge', 'Sprinkles', 'Caramel']});將上述示例與使用數組默認值進行解構的同一函數相對比。
function createSundae([scoops = 1, toppings = ['Hot Fudge']] = []) { … }對于這個函數,如果想使用 scoops 的默認數量,但是更改 toppings,則必須以這種奇怪的方式調用你的函數:
createSundae([undefined, ['Hot Fudge', 'Sprinkles', 'Caramel']]);因為數組是基于位置的,我們需要傳入 undefined 以跳過第一個參數(并使用默認值)來到達第二個參數。
Javascript類
ES5創建類:
function Plane(numEngines) {this.numEngines = numEngines;this.enginesActive = false; }// 由所有實例 "繼承" 的方法 Plane.prototype.startEngines = function () {console.log('starting engines...');this.enginesActive = true; };ES6類只是一個語法糖,原型繼續實際上在底層隱藏起來, 與傳統類機制語言有些區別.
class Plane {//constructor方法雖然在類中,但不是原型上的方法,只是用來生成實例的.constructor(numEngines) {this.numEngines = numEngines;this.enginesActive = false;}//原型上的方法, 由所有實例對象共享.startEngines() {console.log('starting engines…');this.enginesActive = true;} }console.log(typeof Plane); //functionjavascript中類其實只是function, 方法之間不能使用,,不用逗號區分屬性和方法.
靜態方法
要添加靜態方法,請在方法名稱前面加上關鍵字 static
- 關鍵字class帶來其他基于類的語言的很多思想,但是沒有向javascript中添加此功能
- javascript類實際上還是原型繼承
- 創建javascript類的新實例時必須使用new關鍵字
super 和 extends
使用新的super和extends關鍵字擴展類:
class Tree {constructor(size = '10', leaves = {spring: 'green', summer: 'green', fall: 'orange', winter: null}) {this.size = size;this.leaves = leaves;this.leafColor = null;}changeSeason(season) {this.leafColor = this.leaves[season];if (season === 'spring') {this.size += 1;}} }class Maple extends Tree {constructor(syrupQty = 15, size, leaves) {super(size, leaves); //super用作函數this.syrupQty = syrupQty;}changeSeason(season) {super.changeSeason(season);//super用作對象if (season === 'spring') {this.syrupQty += 1;}}gatherSyrup() {this.syrupQty -= 3;} }使用ES5編寫同樣功能的類:
function Tree(size, leaves) {this.size = size || 10;this.leaves = leaves || {spring: 'green', summer: 'green', fall: 'orange', winter: null};this.leafColor; }Tree.prototype.changeSeason = function(season) {this.leafColor = this.leaves[season];if (season === 'spring') {this.size += 1;} }function Maple (syrupQty, size, leaves) {Tree.call(this, size, leaves);this.syrupQty = syrupQty || 15; }Maple.prototype = Object.create(Tree.prototype); Maple.prototype.constructor = Maple;Maple.prototype.changeSeason = function(season) {Tree.prototype.changeSeason.call(this, season);if (season === 'spring') {this.syrupQty += 1;} }Maple.prototype.gatherSyrup = function() {this.syrupQty -= 3; }super 必須在 this 之前被調用
在子類構造函數中,在使用 this 之前,必須先調用超級類。
class Apple {} class GrannySmith extends Apple {constructor(tartnessLevel, energy) {this.tartnessLevel = tartnessLevel; // 在 'super' 之前會拋出一個錯誤!super(energy); } }作者:Showdy
鏈接:https://www.jianshu.com/p/87008f4f8513
來源:簡書
簡書著作權歸作者所有,任何形式的轉載都請聯系作者獲得授權并注明出處。
轉載于:https://www.cnblogs.com/zhanghuajie/p/11093878.html
總結
- 上一篇: 让你一分钟认识电子身份验证系统EID
- 下一篇: VMware、配置VMware vSph