文章目錄
- ES6
- let及const
- 解構賦值
- 模板字串
- Symbol型別
- Set和Map資料結構
- 箭頭函式
- 類
ES6
ES 的全稱是 ECMAScript , 它是由 ECMA 國際標準化組織,制定的一項腳本語言的標準化規范,

ES6 實際上是一個泛指,泛指 ES2015 及后續的版本,
每一次標準的誕生都意味著語言的完善,功能的加強,JavaScript語言本身也有一些令人不滿意的地方,
- 變數提升特性增加了程式運行時的不可預測性
- 語法過于松散,實作相同的功能,不同的人可能會寫出不同的代碼
let及const
1、let: ES6中新增的用于宣告變數的關鍵字,let宣告的變數只在所處于的塊級有效
是ES6新增的宣告格式,用于補全ES5標準中var宣告變數的不足:在JavaScript中用 ‘var’ 來宣告變數會出現變數提升的情況,即通過"var"宣告的變數系統都會把宣告隱式的升至頂部,這樣的特性往往會讓剛接觸JavaScript及習慣其他語言的開發人員不適應,導致程式出現問題,
注意: 使用let關鍵字宣告的變數才具有塊級作用域,使用var宣告的變數不具備塊級作用域特性,
-
ES5中定義作用域有兩種:全域作用域和函式作用域
-
ES6中新增了塊級作用域,用
'{ }'表示,塊級作用域用于宣告作用域之外無法訪問的變數,主要有兩種:-
函式內部塊級作用域:
function test() { let a = 20 } test() console.log(a) // a is not defined -
在字符{ }之間的區域:
{ let a = 10 } console.log(a) // a is not defined
-
例題:
var arr = [];
for (var i = 0; i < 2; i++) {
arr[i] = function () {
console.log(i); //當i的值為2時,不滿足條件,才會跳出回圈,輸出2
}
}
arr[0](); // 2
arr[1](); // 2

關鍵點在于: 變數i是全域的,函式執行時輸出的都是全域作用域下的i值
let arr = [];
for (let i = 0; i < 2; i++) {
arr[i] = function () {
console.log(i);
}
} //回圈結束后產生了兩個塊級作用域,且產生的兩個i處于不同的塊級作用域中,互不影響
arr[0](); //0
arr[1](); //1

關鍵點在于: 每次回圈都會產生一個塊級作用域,每個塊級作用域中的變數都是不同的,函式執行時輸出的是自己上一級(回圈產生的塊級作用域)作用域下的i值
2、const: 使用const宣告的是常量,常量的值不能通過重新賦值來改變,并且不能重新宣告,所以每次通過const來宣告的常量必須進行初始化
-
具有塊級作用域
if (true) { const a = 10; } console.log(a) // a is not defined -
宣告常量時必須賦值
const PI; // Missing initializer in const declaration -
常量賦值后,值不能修改
const PI = 3.14; PI = 100; // Assignment to constant variable.const arry = [100, 200]; arry[0] = 'a'; arry[1] = 'b'; console.log(arry); // ['a', 'b']; arry = ['a', 'b']; // Assignment to constant variable. -
如果宣告的是物件,可以修改物件的屬性值,但不允許修改已經宣告的物件
const obj = { name: '張三', age: 20 } //屬性值是可以直接修改的 obj.name = '李四' console.log(obj) //物件直接修改會報錯 obj = {} // Assignment to constant variable. -
如果讓物件屬性不能修改,可以借助 Object.freeze函式 來 凍結物件
const obj = { name: '張三', age: 20 } Object.freeze(obj); //凍結物件 obj.name = "李四"; //修改屬性 console.log(obj); //結果仍然是{name:'張三',age:20} -
通過Object.freeze凍結物件需要注意的是:不能凍結多層物件
const obj = { name: '張三', age: 20, family: { father: { name: '張安', age: 48 } } } Object.freeze(obj); //凍結物件 obj.family.father.age = 50; //family物件里的屬性不能被凍結 console.log(obj); //物件age的值被改變 -
解決多層凍結問題可以通過封裝一個deepFreeze函式來實作:
const obj = { name: '張三', age: 20, family: { father: { name: '張安', age: 48 } } } function deepFreeze(obj){ Object.freeze(obj); for(let key in obj){ if(obj.hasOwnProperty(key) && typeof obj[key] === 'object'){ deepFreeze(obj[key]) } } } deepFreeze(obj); //凍結物件 obj.family.father.age = 50; //修改物件屬性的值 console.log(obj); //物件age的值未被改變
3、臨時死區:
let和const都是塊級識別符號,所以let和const都是在當前代碼塊內有效,常量不存在變數提升的情況,
但是通過let和const宣告的常量,會放在 臨時死區(temporal dead zone),通過下面代碼可以看出:
{
console.log(typeof a);
let a = 10;
// 報錯:ReferenceError: Cannot access 'a' before initialization
}
即使通過安全的typeof運算子也會報錯,原因是JavaScript引擎在掃描代碼變數時,要么會把變數提升至頂部(遇到 var 宣告),要么會把變數放在臨時死區(遇到 let 和 const 宣告),
因此,這里通過let宣告的’a’變數會被放在臨時死區,所以在宣告之前列印就會報錯
可復習變數提升相關知識:JavaScript 作用域(鏈)、預決議、閉包函式
4、回圈中let和const的使用:
(1)在ES5標準中,for回圈中的回圈變數都是通過var來宣告的,由于var沒有獨立的作用域,導致在回圈中創建函式時會出現結果和思路不一致的情況,如下:
let funArr = []; //該陣列中存放的是函式
for(var i=0;i<5;i++) {
funArr.push(function(){
console.log(i)
})
}
funArr.forEach(item=> {
item()
})
//分行列印了5 5 5 5 5
回圈結果不是預想的0,1,2,3,4,而是5個5,這是因為var宣告在回圈中作用域共用,并且會把i保存在全域作用域中,
(2)要解決回圈中保存函式的問題,可以利用 閉包 創建獨立的作用域,代碼如下:
let funArr = [];
for(var i=0;i<5;i++) {
(
function(i) {
funArr.push(function(){
console.log(i)
})
}
)(i)
}
funArr.forEach(item=> {
item()
})
//分行列印 0 1 2 3 4
這樣通過自執行函式就可以解決回圈中創建函式的問題,
(3)利用ES6中 let 和 const 提供的 塊級作用域 可以讓代碼更簡潔:
let funArr = [];
for(let i=0;i<5;i++) {
funArr.push(function(){
console.log(i)
})
}
funArr.forEach(item=> {
item()
})
//分行列印 0 1 2 3 4
(4)在 for-in或for-of回圈 中使用const時,方法與let一致:
let obj = {
name: '張三',
age: 20
}
for(const i in obj){
console.log(i) //輸出name、age
}
let arr = ['張三','李四','王五']
for(const value of arr){
console.log(value) //輸出張三、李四、王五
}
5、let、const、var 的區別:
- 使用 var 宣告的變數,其作用域為該陳述句所在的函式內,且存在變數提升現象
- 使用 let 宣告的變數,其作用域為該陳述句所在的代碼塊內,不存在變數提升
- 使用 const 宣告的是常量,在后面出現的代碼中不能再修改該常量的值

解構賦值
ES6中允許從陣列中提取值,按照對應位置,對變數賦值,物件也可以實作解構,
1、陣列的解構:
(1) 賦值多個變數
在ES5標準中賦值多個變數采用的方法是:
var a = 10;
var b = 20;
var c = 30;
ES6提供了更簡潔的解構賦值來實作上述變數的定義:
let [a,b,c] = [10,20,30];
等號右邊的值會按照順序依次賦值給左邊的變數,
(2)非一一對應關系的賦值
let [a,b] = [10,20,30]
console.log(a,b); //輸出10,20
let [a,b,c] = [10,20]
console.log(a); //10
console.log(b); //20
console.log(c); //undefined
(3)也可以通過'...'把特定的元素放在變數里
let [a,...arr] = [10,20,30]
console.log(a); //10
console.log(arr); //20,30
(4)可以通過解構賦值來互換變數
let a = 10;
let b = 20;
[a,b] = [b,a];
console.log(a,b)
2、物件的解構:
(1)物件解構的寫法與陣列解構類似
let obj = {
name: '張三',
age: 20,
height: '178com'
}
let { name,age,height } = obj; //變數的名稱必須和物件的屬性名相同
console.log(name,age,height);
(2)也可以解構多層物件
let person = {
name: '張三',
age: 20,
family: {
father: '張武',
mother: '李燕'
}
}
let { name,age,family: {father,mother }} = person
console.log(name,father)
(3)在解構物件時也可以自定義變數名稱:
let obj = {
name: '張三',
age: 20
}
let { name:myname,age:myage } = obj;
console.log(myname,myage);
3、解構的默認值和引數的解構:
(1)不管是陣列的解構賦值,還是物件的解構賦值都可以添加默認引數,如下:
let obj = {
name: '李四',
age: 20
}
let { name,age,height="178com" } = obj;
console.log(height); //178com
(2)在函式引數中使用解構,引數解構也可以給默認引數
function fun({name,age,height="178com"} = {}){
console.log(name,age); //張三,20
}
let obj = {
name: '張三',
age: 20
}
fun(obj)
模板字串
ES5標準中一般輸出模板是通過字串拼接的方式進行的,
在ES6中可以通過模板字串簡化字串的拼接,模板字串通過反引號來表示'``',如果要嵌入變數通過'${ 變數名 }'來實作:
let arr = [
{
name: '張三',
age: 20
},
{
name: '李四',
age: 23
},
{
name: '王五',
age: 25
}
]
let str = "";
for(let i=0;i<arr.length;i++){
str += `姓名是:${ arr[i].name },年齡是:${ arr[i].age }`;
}
console.log(str)
//姓名是:張三,年齡是:20姓名是:李四,年齡是:23姓名是:王五,年齡是:25
Symbol型別
ES5中提供了 6種資料型別 分別是:undefined、null、boolean、string、number、object
ES6中新增了一種資料型別Symbol來表示唯一的值,每個創建的Symbol都是唯一的,這樣在實際運用中可以創建一些唯一的屬性及定義私有變數,例如:
let s1=Symbol; //直接創建
let s2=Symbol('s2'); //傳入字串創建
let s3=Symbol('s2');
console.log(s1); //[Function: Symbol]
console.log(s2); //Symbol(s2)
console.log(s2===s3) //false
1、目前前端專案都會采用模塊化構建,為了防止物件屬性名被覆寫,可以通過symbol來定義屬性名,例如:
//a.js
const NAME = Symbol('name')
let obj = {
[NAME]:'張三',
age: 20
}
module.export = obj;
//b.js
import obj from './a.js'
const NAME = Symbol('name');
obj[NAME] = '李四';
console.log(obj); //{age:20,Symbol():'張三',Symbol():'李四'}
2、利用Symbol作為屬性名,屬性名不會被 Object.keys()、Object.getOwnPropertyNames()、for…in回圈回傳,例如:
let obj={
[Symbol('name')]:'張三',
age:40,
height:'178cm'
}
for(let key in obj){ //for...in回圈不能回傳Symbol屬性
console.log(key); //age 40
console.log(obj[key]); //height 178cm
}
let keys=Object.keys(obj); //提取obj物件所有可列舉屬性名
console.log(keys); //[ 'age', 'height' ]
let name=Object.getOwnPropertyNames(obj);//獲取obj物件所有屬性名
console.log(name); //[ 'age', 'height' ]
3、可以在類里利用Symbol來 定義私有屬性及方法例如:
let People=(
function(){
let name=Symbol('name');
class p{
constructor(yourname){
this[name]=yourname;
}
sayName(){
console.log(`姓名:${this[name]}`)
}
}
return p
}
)();
//對上述代碼的拆分:
//原理是:閉包+匿名函式
// function fun(){
// let name=Symbol('name');
// class p{
// constructor(yourname){
// this[name]=yourname;
// }
// sayName(){
// console.log(`姓名:${this[name]}`)
// }
// }
// return p
// }
// let People=fun();
let p1=new People('張三'); //呼叫構造方法
console.log(p1[Symbol('name')]); //undefined
p1.sayName();
Set和Map資料結構
1、Set
Set類似于陣列,但是它里面每一項的值是唯一的,沒有重復的值,set是一個建構式,用來生成set的資料結構
let s = new Set();
let arr = [2, 3, 5, 4, 5, 2, 2];
arr .forEach(item => arr.add(item)); //向set添加重復的值
for (let i of s) {
console.log(i);
}
// 2 3 5 4 結果set不會添加重復的值
4種操作方法:
- add(value):添加某個值,回傳 Set 結構本身
- delete(value):洗掉某個值,回傳一個布林值,表示洗掉是否成功
- has(value):回傳一個布林值,表示該值是否為 Set 的成員
- clear():清除所有成員,沒有回傳值
4種遍歷方法:可用于遍歷成員
- keys():回傳一個鍵名的遍歷器
- values():回傳一個鍵值的遍歷器
- entries():回傳一個鍵值對的遍歷器
- forEach(): 使用回呼函式遍歷每個成員
注意: 由于Set結構沒有鍵名,只有鍵值(或者說鍵名和鍵值是同一個值),所以keys方法和values方法的行為完全一致,
實作并集(Union)、交集(Intersect)、差集(Difference):
let a = new Set([1, 2, 3]);
let b = new Set([4, 3, 2]);
//并集
let union = new Set([...a, ...b]);
//[1, 2, 3, 4]
//交集
let intersect = new Set([...a].filter(x => b.has(x)));
//[2,3]
//差集
let difference = new Set([..a].filter(x => !b.has(x))); //交集取反
//[1]
2、Map
JavaScript的物件(Object)本質上是鍵值對的集合(Hash結構),但是只能用字串作為鍵,這給它的使用帶來了很大的限制,
為了解決這個問題,ES6 提供了Map資料結構,它類似于物件,也是鍵值對的集合,但是“鍵”的范圍不限于字串,各種型別的值( 包括物件)都可以當作鍵,也就是說,Object 結構提供了“字串一值”的對應,Map結構提供了“值一值"的對應,是種更完善的Hash結構實作,
var m= new Map();
var o ={p: "Hello World"};
m.set(o, "content")
m.get(o) // "content"
m.has(o) // true
m.delete(o) // true
m.has(o) // false
操作方法:
- size屬性:回傳Map結構的成員總數
- set(key, value):設定key所對應的鍵值,然后回傳整個Map結構,如果key已經有值,則鍵值會被更新,否則就新生成該鍵
- get(key):讀取key對應的鍵值,如果找不到key,則回傳undefined
- has(key):回傳一個布林值,表示某個鍵是否在Map資料結構中
- delete(key):洗掉某個鍵,回傳true,如果洗掉失敗,則回傳false
- clear():清除所有成員,沒有回傳值
4種遍歷方法:可用于遍歷成,
- keys(): 回傳一個鍵名的遍歷器
- values(): 回傳一個鍵值的遍歷器
- entries(): 回傳一個鍵值對的遍歷器
- forEach(): 使用回呼函式遍歷每個成員
箭頭函式
1、函式形參的默認值:在很多情況下,需要在使用函式的時候給定默認引數
在ES5標準中:
function fun(name,age,cb){
name = typeof(name !== 'undefined')?name: '張三'
age = typeof(age !== 'undefined')?age: 20
cb = typeof(cb !== 'undefined')?cb:function(){}
console.log(name,age); //列印結果:張三 20
}
fun("李四",0)
ES6中函式默認引數:
function fun(name='張三',age=20,cb){
console.log(name,age)
}
fun();
2、函式形參不定引數:在很多情況下,使用函式傳參的時候,形參的數量是不固定的,這時候要獲取引數值就會比較麻煩,
在ES5標準中可以通過 隱藏引數arguments 來獲取,此時會把所有引數放在arguments中,例如:
function fun() {
console.log(arguments); //列印結果:[Arguments] { '0': '張三', '1': 20, '2': '178cm' }
console.log(arguments[0]); //第一個引數 列印結果:李四
console.log(arguments[1]); //第二個引數 列印結果:20
console.log(arguments[2]); //第三個引數 列印結果:178cm
}
fun('張三',20,'178cm')
3、箭頭函式:箭頭語法最大的特點是有箭頭=>符號,當然箭頭語法有很多變式寫法:const fn = () => {}
(1) 沒有引數,用括號代替 若只有一句,不帶花括號,自帶return
let fun = ()=> "張三"
(2) 一個引數,括號可以省略
let fun = arg=> "李四"
(3) 多個引數
let fun = (arg1,arg2)=> arg1 + arg2
console.log(fun(1,3)) // 列印結果:4
(4) 利用箭頭語法里隱式返還的時候需要注意物件的情況,需要注意如下錯誤情況:
//錯誤寫法
let fun = () => {
name: '張三',
age: 20
}
自認為返還的是一個物件,但是這里的大括號和函式里的大括號在含義上有沖突,系統會認為大括號是 函式里的括號,而不是物件里的括號,導致報錯
let fun = () => ({
name: '張三',
age: 20
})
console.log(fun());
(5) 箭頭函式里沒有this系結,箭頭函式中的this,指向的是 函式定義位置的背景關系this
let obj = {
id: 2,
fun: function() {
console.log(this.id); // 輸出:2
}
}
obj.fun()
上面代碼可以列印出id為2,this指向了obj,所以this.id可以取得obj.id,如果改成箭頭語法會發現,函式中this指向改變了,代碼如下:
let obj = {
id: 2,
fun: ()=>{
console.log(this.id); //輸出:undefined
}
}
obj.fun()
this.id 獲取不到值,原因是:箭頭函式沒有this系結,箭頭函式中的this會指向最近的上層this,即this的指向是window
(6) 使用箭頭語法的時候 沒有隱藏引數arguments的系結,代碼如下:
let fun = (arg1,arg2) => {
console.log(arguments); // arguments is not defined
return arg1 + arg2
}
fun()
類
在ES5標準中通過建構式來模擬類的功能,一般會定義一個建構式,把一類功能做封裝,通過new運算子來呼叫
//ES5中類定義
function Person(name){
this.name=name,
this.age=20
}
Person.prototype.fun=function(){
console.log('ES5中類定義...') //列印結果:ES5中類定義...
}
let p1=new Person();
p1.fun()
在ES6標準中提供class關鍵字來定義類,在寫法上更簡潔、語意化更強
//ES6中類定義 set get方法
class Person{
constructor(name,age){
this.name=name;
this.age=age;
}
get myage(){
return this.age;
}
set myage(newAge){
this.age=newAge
}
fn(){
console.log('ES6中類定義...') //列印結果:ES6中類定義...
}
}
let p1=new Person('李四',28);
p1.fn();
console.log('年齡:'+p1.myage); //列印結果:年齡:28
ES6支持通過getter、setter在原型上定義屬性,創建getter的時候需要用關鍵字get,創建setter的時候需要用關鍵字set
類的靜態屬性、靜態方法為類的所有物件共享,而不屬于某個具體的物件
class Student{
static schoolName = '加州大學'; //靜態屬性 所有物件共享
constructor(name,age){
this.name=name;
this.age=age;
}
static showSchoolName(){ //靜態方法
console.log(this.schoolName) //列印結果:加州大學
}
showStudent(){
console.log(`姓名:${this.name} 年齡:${this.age}`); //列印結果:姓名:張三 年齡:20
}
}
let s1=new Student('張三',20);
Student.showSchoolName();
s1.showStudent();
繼承:
在ES5標準中可以通過call、apply、bind來實作建構式的繼承,實作方式如下
function Dad(name,age){
this.name=name;
this.age=age;
}
function Son(name,age=25){
Dad.call(this,name,age) //實作構造方法的繼承
this.height='178cm';
}
Son.prototype.show=function(){
console.log(this.name); //張三
console.log(this.age); //25
}
let s1=new Son('張三')
s1.show()
上述方式可以實作建構式的繼承,但是如果有方法在Dad原型上實作,還需要考慮原型的繼承,單純的原型賦值繼承還會涉及傳址問題,所以實作起來比較繁瑣
ES6標準中類的繼承:通過extends關鍵字實作
class Dad{
constructor(name){
this.name=name;
}
fun(){
console.log('父類的成員方法...')
}
}
class Son extends Dad{
constructor(name){
super(name);
}
hobby(){
console.log('籃球');
}
show(){
super.fun();
console.log(`姓名:${this.name}`);
}
}
let s1=new Son('張三');
s1.show();
在繼承中需要呼叫super()方法繼承父類的構造方法,super()在使用程序中需要注意以下兩點:
- 在訪問this之前一定要呼叫super()
- 如果不呼叫super(),可以讓子類建構式返還一個物件
轉載請註明出處,本文鏈接:https://www.uj5u.com/qianduan/302248.html
標籤:其他
上一篇:快速入坑ES6
下一篇:vueAdmin前端學習筆記
