ECMAScript 6.0(以下簡稱 ES6)是 JavaScript 語言的下一代標準,已經在 2015 年 6 月正式釋出了。 它的目標,是使得 JavaScript 語言可以用來編寫複雜的大型應用程式,成為企業級開發語言。
ECMAScript和JS的關係 ECMAScript是標準,JS是實現
- 類似於HTML5是標準,IE,chrome是實現 例如國家定了醫用口罩標準(需要過濾XX,等等各種引數),我們們買的正規口罩是實現
- 目前ECMAScript除了JS還沒別的實現,所以ECMAScript==JS也說得過去
- ES6釋出於2015年釋出,所以也可以叫es2015 去年的ES2021 是ES12 但是主要的改變是在es6,這幾年的東西都增加的不多,所以把ES6以及以後的版本統稱為es6也合理,ES2022也也即將推出
今天對我目前所知的並且常用的一些做一個總結,適合處於新手村和即將走出新手村的兄弟觀看學習,同時也歡迎各位大佬補充
1、宣告變數
首先說說在沒有es6之前存在的問題,也就是var的問題
- 可以重複定義
- 無法限制修改,有些東西不會變化,沒常量
- 沒有塊級作用域,只有函式作用域
- 變數提示帶來的混亂
es6新增了兩個宣告變數關鍵字,let和const 這兩個關鍵字就是為了解決es5存在的問題
let
(1)let 宣告變數時只在其塊級作用域中有效
1 { 2 let a = 10; 3 var b = 1; 4 } 5 console.log(a); //出錯 not defined 6 console.log(b); //1
在es5中如果要實現塊級作用域,通常藉助立即執行匿名函式來實現
1 (function(){ 2 var a = 1; 3 }()); 4 console.log(a); //出錯,not defined
但是有了let之後,就可以解決這麼問題
(2)沒有變數提升
也正是如此,變數必須在宣告後使用,否則就會報錯,這裡對比var經典的變數提升
//let console.log(a); //出錯, not defined let a = 1;
//var console.log(a); //undefined var a =1;
(3)不可以在相同作用域內重複宣告同一個變數,也包括不能和var,const變數名重複
let a = 1; let a = 1; //出錯 let不可重複宣告 var b = 1; let b = 1; //出錯 let不可重複宣告 const c = 1; let c = 1; //出錯 let不可重複宣告
(4)在塊級作用域內,若存在用let命令宣告的變數,則所在區塊對該變數形成封閉作用域,也就是該變數無視外部的同名變數。而又因為不存在變數提升,所以在該區塊中,不能在宣告前使用該變數。
var a = 1; if(true){ a = 2; //出錯 not defined let a; }
var a = 1; if(true){ a = 2; //var允許重複宣告,而且變數提升,故a=2正常賦值 var a; }
const
const和let的區別在於const宣告的變數不能修改,let宣告的變數可以修改
const name = "?"; //name = '2' //報錯 //但是也不是都不能變 const person = { name:"?" } person.name="?"; console.log(person) //const實際上保證的,並不是變數的值不得改動,而是變數指向的那個記憶體地址所儲存的資料不得改動。 //對於簡單型別的資料(數值、字串、布林值),值就儲存在變數指向的那個記憶體地址,因此等同於常量。 //但對於複合型別的資料(主要是物件和陣列),變數指向的記憶體地址,儲存的只是一個指向實際資料的指標, //const只能保證這個指標是固定的(即總是指向另一個固定的地址), //至於它指向的資料結構是不是可變的,就完全不能控制了。因此,將一個物件宣告為常量必須非常小心。
學會之後推薦宣告變數時使用let,可以避免很多不必要的麻煩,const看個人需求
2、Symbol
ES6新增了一個基本資料型別:Symbol,至此ECMAScript的基本資料型別就有了6種: 字串,數字,布林,null,undefined,Symbol。
//Symbol 的定義不能使用new 他使用Symbol()函式生成 let a = Symbol(); typeof a // "symbol" //Symbol建立時可以傳一個引數,表示對Symbol的描述 let s1 = Symbol('a'); let s2 = Symbol('b'); s1 // Symbol(a) s2 // Symbol(b)
Symbol表示獨一無二的值
1 let s1 = Symbol('a'); 2 let s2 = Symbol('a'); 3 4 //s1===s2 false; 5 //既然Symbol的值都不相等 那麼可以利用他的特性解決物件裡同名覆蓋的問題 6 7 let obj = { 8 [Symbol()]: 1 9 }; 10 //或者 11 let s = Symbol(); 12 let obj = { 13 [s]: 1 14 };
Symbol.for() 有時,我們希望重新使用同一個 Symbol 值,Symbol.for()方法可以做到這一點。 它接受一個字串作為引數,然後搜尋有沒有以該引數作為名稱的 Symbol 值。 如果有,就返回這個 Symbol 值,否則就新建一個以該字串為名稱的 Symbol 值,並將其註冊到全域性。
1 let s1 = Symbol.for('a'); 2 let s2 = Symbol.for('a'); 3 4 s1 === s2 // true 5 6 //兩種寫法區別 7 Symbol.for("a") === Symbol.for("a") // true 8 9 Symbol("a") === Symbol("a") //false
3、解構賦值(常用)
1 let [a,b,c] = [1,2,3] 2 var [a,,c]=[1,2,3]; 3 console.log(a+' | '+c); //1 | 3 4 var [a,...b]=[1,2,3]; 5 console.log(a+' | '+b);//1 | 2,3 6 console.log(b);//[2, 3] 7 // ...將右側多餘的值以陣列的形式賦值給左側變數 rest 8 9 //設定預設值 10 var [a,b,c='default',d='default']=[1,2,3]; 11 console.log(a+' | '+b+' | '+c+' | '+d);//1 | 2 | 3 | default 12 13 //找不到的會被賦值為undefined 14 var [a,b,c]=[1,2]; 15 console.log(a+' | '+b+' | '+c);//1 | 2 | undefined
物件的解構賦值
1 //物件的解構賦值 2 3 let obj={ 4 a:1, 5 b:2 6 } 7 let {a,b}=obj; 8 console.log(a+" | "+b);//1 | 2 9 10 //重新命名,把obj.a重新命名為A 11 let obj={ 12 a:1, 13 b:2 14 } 15 let {a:A,b}=obj; 16 console.log(A+" | "+b);//1 | 2 17 console.log(a);//Uncaught ReferenceError: a is not defined 18 19 //設定預設值 20 21 let {a=1,b=2}={a:10}; 22 console.log(a+" | "+b);//10 | 2 23 24 //字串也可以解構 25 26 var [a,b,c,d,e]='nihao'; 27 console.log(a);//
4、函式預設值
1 //es5寫法 2 function sum(a,b){ 3 b= b||0; 4 console.log(a+b) 5 } 6 7 sum(1) 8 9 //es6 10 function sum(a,b=0){ 11 console.log(a+b) 12 } 13 sum(1) 14 function sum(a=2,b=0){ 15 console.log(a+b) 16 } 17 18 sum()
5、箭頭函式(常用)
箭頭函式都是匿名函式
1 function show(num){ 2 return num*num 3 } 4 var show = function(num){ 5 6 return num*num 7 } 8 9 //如果箭頭函式不需要引數或需要多個引數,就使用一個圓括號代表引數部分。 提個引數可以去掉括號 10 var show =(num)=>{ 11 return num*num 12 } 13 //如果只有一條return語句,可以省略大括號和return 隱式返回 14 15 var show =num=>num*num; 16 17 18 19 //箭頭函式的this繼承自他的父作用域 20 //而且與我們原來普通函式不同,原來的函式this是呼叫時動態指定的, 21 //而箭頭函式是詞法作用域,他裡的this是定義時就指定的 而且不會隨著呼叫方式不同而改變 22 23 //如下例子 24 var log_this = ()=>{ 25 26 console.log(this) 27 } 28 var log_this = function(){ 29 30 console.log(this) 31 } 32 33 var obj = { 34 hobbies:['code','run','paly game'], 35 logHobbies:log_this 36 } 37 38 39 obj.logHobbies() 40 41 42 log_this()
有幾點需要注意
-
函式體內的this物件,就是定義時所在的物件,而不是使用時所在的物件。
-
不可以當作建構函式,也就是說,不可以使用new命令,否則會丟擲一個錯誤。
-
不可以使用arguments物件,該物件在函式體內不存在。如果要用,可以用 rest 引數代替。
-
不可以使用yield命令,因此箭頭函式不能用作 Generator 函式。
- 上面四點中,第一點尤其值得注意。this物件的指向是可變的,但是在箭頭函式中,它是固定的。
6、模板字串(常用)
原來寫字串比較痛苦 特別是拼接變數時
1 const name="小?"; 2 const age = 2; 3 4 console.log('ta的名字是'+name+',它今年'+age+'了'); 5 console.log('<div data-age="'+age+'">'+name+'</div>');//這種更難受 6 console.log(`ta的名字是${name},它今年${age}了`) 7 console.log(`<div data-age="${age}">${name} 8 </div>`)
模板字串可以巢狀
1 var arr = [{ 2 name:"蘋果", 3 price:11 4 },{ 5 name:"香蕉", 6 price:12 7 }]; 8 9 10 var template = ` 11 <ul> 12 ${arr.map(v=>` 13 <li>${v.name} 14 <span>${v.price}</span> 15 </li> 16 `).join('')} 17 </ul> 18 ` 19 20 console.log(template) 21 22 document.body.innerHTML = template;
7、陣列
spread 展開運算子也是三個點(...)。它好比 rest 引數的逆運算,將一個陣列轉為用逗號分隔的引數序列。
1 const a = [1, 2, 3]; 2 const b = [4,5,6]; 3 const c = [...a] // [1,2,3] 4 //輕鬆拼接兩個陣列 5 const d = [...a,...b] // [1,2,3,4,5,6] 6 7 8 //類陣列物件變成陣列 9 var list=document.getElementsByTagName('a'); 10 var arr=[...list];
其實不單單是引數可以展開,對於物件和字串同樣可以展開
1 const obj1 = { a: 111, b: 222 }; 2 const obj2 = { c: 333, d: 444 }; 3 const merged = { ...obj1, ...obj2 }; 4 console.log(merged); // -> { a: 111, b: 222, c: 333, d: 444 } 5 //或者這樣 6 const others = {third: 3, fourth: 4, fifth: 5} 7 const items = { first:1, second:1, ...others } 8 items //{ first: 1, second: 2, third: 3, fourth: 4, fifth: 5 } 9 10 11 //展開字串 12 13 const str = 'hello' 14 const array_str_ = [...str] //
- Array.from
1 //Array.from方法用於將兩類物件轉為真正的陣列 2 var args = Array.from(arguments); 3 var list = Array.from(document.querySelectAll('li'));
- Array.of()
1 //這個方法的主要目的,是彌補陣列建構函式Array()的不足。因為引數個數的不同,會導致Array()的行為有差異。 2 Array() // [] 3 Array(3) // [, , ,] 4 Array(3, 11, 8) // [3, 11, 8] 5 6 Array.of(3, 11, 8) // [3,11,8] 7 Array.of(3) // [3] 8 Array.of(3).length // 1
8、for of 迴圈
1 看一下我們們會的迴圈方法 2 for 無法迴圈物件 3 for in 存在問題 他會遍歷所有可遍歷屬性 如果為原型加了一些屬性,那也會遍歷出來 4 forEach 迴圈陣列 無法終止 5 6 最終es6為了統一,也借鑑了c++,java,python語言引入了for of迴圈 作為遍歷所有資料結構的統一的方法。 7 for...of迴圈可以使用的範圍包括陣列、Set 和 Map 結構、 8 某些類似陣列的物件(比如arguments物件、DOM NodeList 物件)、 9 後文的 Generator 物件,以及字串。 10 -- 物件不能使用for of
1 for(let v of [1,2,3]) { 2 console.log(v); // 1 2 3 3 } 4 let p = document.querySelectorAll("p"); 5 for (let x of p) { 6 console.log(x); 7 }
9、set
1 //ES6 提供了新的資料結構 Set。它類似於陣列,但是成員的值都是唯一的,沒有重複的值。 2 3 const set = new Set([1, 2, 2, 4, 4]); 4 [...set] 5 //用Set 去重非常方便 ,陣列去重面試常考題 6 7 [...new Set(arr)]
今天先寫這麼多,剩下的物件導向、promise、模組化和map等以後有機會再補充,公司又有新需求了,我得去寫程式碼了(表示是被迫停下來,不是故意留一些不寫的),後邊的這些都是個人感覺都是重點,等我程式碼寫完再來補充,同時有哪些問題歡迎各位大佬提醒,畢竟我也還只是一隻菜鳥,只是對自己的理解做一下總結