玩轉ES6新特性

前面有座山發表於2018-08-11

程式語言是向後相容的,相對於ES5,ES6增加了一些新的特性,下面簡單介紹一些

  • let 和 const 命令

  • 變數的解構賦值

  • 模板字串

  • 陣列新增的方法

  • 字串新增的方法

  • class建立物件以及繼承

  • 箭頭函式

  • Set 和 Map


1. let 和 const 命令

首先我們要知道這兩個命令是用來做什麼的:
let:定義一個變數;
const:定義一個常量。
在ES6之前我們定義一個變數使用的是關鍵字var,那麼有人會說ES6這樣是不是多此一舉呢?
當然不是,各有各的特點不能說誰一定好,要根據適應的環境來使用。它們的主要不同就是變數提升作用域。下面我們通過程式碼來具體感受一下。

變數提升

我們來看下面的程式碼來看一下var和let定義的變數。

console.log(b); //undefined
var b = 100;
複製程式碼

根據上面的程式碼,我們知道瀏覽器的js引擎執行緒是根據程式碼結構執行的,那麼在執行的時候列印出來的應該是not defined,為什麼是undefined?undefined是一個基本資料型別,是在我們定義了這個變數沒有賦值的情況下才會列印出來。那麼這裡就存在一個我們在ES5中說的變數提升。什麼是變數提升?變數提升可以分兩個步驟:1、定義。2、執行。也就是說在程式碼開始執行的時候瀏覽器會先檢測整個程式碼,將定義部分提前,然後再去完成執行部分。所以上面程式碼的實際執行:如下:

var b;
console.log(b);
b = 100;
複製程式碼

如果我們使用let來定義呢?

console.log(b)    //b is not defined
let b = 100
複製程式碼

列印出來 b is not defined,說明並沒有之前的變數提升,這裡嚴格按照先定義後執行的順序。

作用域

變數或者函式都有自己的作用域。在ES6中新增了一個新的概念:塊級作用域
在這之前只用全域性作用域以及區域性作用域。根據函式來區分,定義在函式裡面的變數的作用域叫做區域性作用域,定義在全域性的變數叫做全域性作用域。
那麼塊級作用域怎麼區別呢?

{
    let a = 100;
    console.log(a)  //100
}
console.log(a)   //a is not defined
複製程式碼

上面的程式碼就是一個塊級作用域,我們通過{}來區別。一個{}就是一個作用域。 下面我們來看一段程式碼來區別一下let 和 var 定義的變數的作用域。

//  程式碼一
var a = []
 for(var i  = 0; i < 3; i ++ ){
     a[i] = function(){
         console.log(i)
     }
 }
 a[0]();   //3
 a[1]();   //3
 a[2]();   //3
複製程式碼

我們希望的是a[0]()能夠輸出 0a[1]()能夠輸出 1,a[2]()能夠輸出 2,上面程式碼中,變數i只用來控制迴圈,但是迴圈結束後,它並沒有消失,洩露成了全域性變數也就是這個i會一直存在。這是我們很不希望見到的。

//程式碼二
    let a = []
     for(let i  = 0; i < 3; i ++ ){
         a[i] = function(){
             console.log(i)
         }
     }
     a[0]();   //0
     a[1]();   //1
     a[2]();   //2
複製程式碼

上面的程式碼很好理解,for迴圈下面是一個{}程式碼塊,也就相當於一個作用域,每一個作用域裡面的i值互不影響。畫圖理解一下兩段程式碼。

玩轉ES6新特性

在程式碼一中,使用var定義的i,當for迴圈執行完畢,i的值也隨著變化,最後的i值等於3 那麼之前a[i]中的i值也會變化.但是程式碼二使用let定義的i會在{ }中形成自己的作用域,不會因為父作用域數值的改變去改變自己本身的值,所以可以按照需求輸出。

當然在塊級作用域下使用函式宣告定義的函式還是會提升的,這點要注意,不能混淆。

const

const 是用來定義一個常量,它的作用域和let是一樣的,但是他們的區別在於,let可以先定義變數,在使用的過程中賦值,而const必須在定義的同時賦值,不能二次賦值。 如下:

//正確的用法
const p = 3.1;
console。log(p) //3.1
複製程式碼
//錯誤的用法
const a;
a = 2;
console.log(a) //
//Missing initializer in const declaration       
複製程式碼

如果是引用性資料型別的話,const定義的常量儲存的是記憶體地址。這點要記住。

2. 變數的解構賦值

什麼是解構賦值,簡單點理解就是一次性給多個變數賦值。

平時我們賦值的時候一般是這樣的

let a = 1;
let b = 2;
let c = 3;
複製程式碼

這樣賦值沒問題但是卻增加了程式碼量,在ES6中允許

let [a,b,c] = [1,2,3]
複製程式碼

上面程式碼表示,可以從陣列中提取值,按照對應位置,對變數賦值。

本質上,這種寫法屬於“模式匹配”,只要等號兩邊的模式相同,左邊的變數就會被賦予對應的值。下面是一些使用巢狀陣列進行解構的例子。

let [foo, [[bar], baz]] = [1, [[2], 3]];
foo // 1
bar // 2
baz // 3

let [ , , third] = ["foo", "bar", "baz"];
third // "baz"

let [x, , y] = [1, 2, 3];
x // 1
y // 3

let [head, ...tail] = [1, 2, 3, 4];
head // 1
tail // [2, 3, 4]

let [x, y, ...z] = ['a'];
x // "a"
y // undefined
z // []

複製程式碼

如果解構不成功,變數的值就等於undefined。

let [foo] = [];
let [bar, foo] = [1];
複製程式碼

左右結構要一一對應

let [x, y] = [1, 2, 3];
x // 1
y // 2

let [a, [b], d] = [1, [2, 3], 4];
a // 1
b // 2
d // 4
複製程式碼

可以設定預設值,如果後面繼續賦值的話會被覆蓋掉。

let [a,b=2] = [1]
a //1
b //2
let [c,d = 3] = [1,5]
c //1
d //5
複製程式碼

給物件解構賦值

物件是一個無序的屬性集合,所以在給物件解構賦值的時候要和屬性名字一一對應。

let { bar, foo } = { foo: "aaa", bar: "bbb" };
foo // "aaa"
bar // "bbb"
複製程式碼

變數之間的賦值

let [x = 1, y = x] = [];     //x=1, y=1
let [x = y, y = ] = [];      //報錯
複製程式碼

上面的程式碼提示我們變數之間互相賦值的時候,賦值的變數必須是已經定義好的。 一個小的應用變數直間相互賦值的特性一個小的敲門

//將x,y的值調換
let x = 1;
let y = 2;
[x,y] = [y,x]
複製程式碼

字串之間的賦值

const [a, b, c, d, e] = 'hello';
a // "h"
b // "e"
c // "l"
d // "l"
e // "o"
//類似陣列的物件都有一個length屬性,因此還可以對這個屬性解構賦值。
let {length : len} = 'hello';
len // 5
複製程式碼

函式傳參時候的解構賦值

function add([x, y]){
  return x + y;
}

add([1, 2]); // 3
複製程式碼

總而言之,在使用解構賦值的時候一定要一一對照

3. 模板字串

模板字串使用反引號 () 來代替普通字串中的用雙引號和單引號。模板字串可以包含特定語法(${})的佔位符

let obj = {
    name : "xiaoxiao",
    age  : 15
}
console.log(`我叫${obj.name}今年${obj.age}歲了`)
複製程式碼

4. 陣列新增的方法

Array.isArray()

作用:判斷是否是陣列

let arr = [1,2,3]
console.log(Array.isArray(arr))    //true
複製程式碼

Array.from()

這個方法是Array構造器的靜態方法,作用:將類陣列物件轉化成真正的陣列

let obj = "hello"
console.log(Array.isArray(obj))   //false
let arr = Array.from(obj)         //[ 'h', 'e', 'l', 'l', 'o' ]
console.log(arr)
console.log(Array.isArray(arr))   //true

複製程式碼

Array.of()

作用:將一組值轉換為陣列

let arr1 = Array.of(3)
let arr2 = Array.of("3")
let arr3 = Array.of(1,2,3)
console.log(arr1,arr2,arr3)  //[ 3 ] [ '3' ] [ 1, 2, 3 ]
複製程式碼

find和findlndex

find:用於找出第一個符合條件的陣列元素。找不到則是 undefined ;只要找到一個就會終止。如果需要全部找出來需要用filter();

findIndex:返回第一個符合條件的陣列元素的索引。找不到則是-1;

和indexof有異曲同工之妙,indexOf返回的是索引


let arr = [4,3,2,1]
let rs = arr.find(function(item,index){

    return item ==2;
})
let rt = arr.findIndex(function(item,index){
    return item == 3
})
console.log(rs)    //2
console.log(rt) //1
複製程式碼

indexOf

//indexof
let arr = [1,2,6,8]
console.log(arr.indexOf(6))   //2
複製程式碼

includes

作用:判斷元素是否在陣列中存在。返回值是 true|false

let arr = [1,2,6,8]
console.log(arr.includes(6))   //true
複製程式碼

fill

作用:給陣列填充指定值。fill 方法用於空陣列的初始化非常方便。但是已有資料會被覆蓋。 fill 方法還可以接受第二個和第三個引數,用於指定填充的起始位置和結束位置

玩轉ES6新特性

let arr1 = new Array(5)
arr1.fill("*")
console.log(arr1)    //[ '*', '*', '*', '*', '*' ]
//覆蓋原有資料
let arr2 = [1,2,3]
arr2.fill("*")
console.log(arr2)  //[ '*', '*', '*' ]
複製程式碼

陣列的擴充套件運算子

功能:把資料結構轉成陣列。和Array.from()的功能相似

let arr = "hello"
let arr2 = [...arr]
console.log(arr2)    //[ 'h', 'e', 'l', 'l', 'o' ]
console.log(Array.isArray(arr2))  //true

複製程式碼

擴充套件運算子連結陣列

let arr1 = [1,2]
let arr2 = [3,4]
let arr = [...arr1,...arr2]
console.log(arr)    [ 1, 2, 3, 4 ]
複製程式碼

注意:在使用擴充套件運算子的時候必須要用容器將其包括起來。

map

獲取一個新的陣列

//將成績加10並返回
let arr = [
    {name:"aa",score:11},
    {name:"bb",score:22},
    {name:"cc",score:22},
    {name:"dd",score:52},
    {name:"ee",score:45},
    {name:"ff",score:34},
    {name:"gg",score:77},
    {name:"hh",score:88},
]

let rs = arr.map((item,index,arr) => {
    return item.score += 10 
})
// let rs =arr.map((item,index,arr) => {
//     return arr

// })

console.log(rs)   //[ 21, 32, 32, 62, 55, 44, 87, 98 ]
複製程式碼

5. 字串新增的方法

includes(),startWith(),endsWith()

includes():返回布林值,表示是否找到了引數字串。
startsWith():返回布林值,表示引數字串是否在原字串的頭部。。
endsWith():返回布林值,表示引數字串是否在原字串的尾部。。

 let s = 'Hello world!';

s.startsWith('Hello') // true
s.endsWith('!') // true
s.includes('o') // true

複製程式碼

這三個方法都支援第二個引數,表示開始搜尋的位置。

let s = 'Hello world!';

s.startsWith('world', 6) // true
s.endsWith('Hello', 5) // true
s.includes('Hello', 6) // false
複製程式碼

上面程式碼表示,使用第二個引數n時, endsWith的行為與其他兩個方法有所不同。 它針對前n個字元,而其他兩個方法針對從第n個位置直到字串結束。

repeat()

repeat方法返回一個新字串,表示將原字串重複n次。

'x'.repeat(3) // "xxx"
'hello'.repeat(2) // "hellohello"
'na'.repeat(0) // ""

  //引數如果是小數,會被取整。

'na'.repeat(2.9) // "nana"
複製程式碼

padStart(),padEnd()

padStart()用於頭部補全,padEnd()用於尾部補全。

'x'.padStart(4, 'ab') // 'abax'
'x'.padEnd(5, 'ab') // 'xabab'
複製程式碼

上面程式碼中,padStart和padEnd一共接受兩個引數,第一個引數用來指定字串的最小長度,第二個引數是用來補全的字串。

如果原字串的長度,等於或大於指定的最小長度,則返回原字串。

'xxx'.padStart(2, 'ab') // 'xxx'
'xxx'.padEnd(2, 'ab') // 'xxx'
複製程式碼

如果用來補全的字串與原字串,兩者的長度之和超過了指定的最小長度,則會截去超出位數的補全字串。

'abc'.padStart(10, '0123456789')
// '0123456abc'
複製程式碼

如果省略第二個引數,預設使用空格補全長度。

'x'.padStart(4) // '   x'
'x'.padEnd(4) // 'x   '
複製程式碼

padStart的常見用途是為數值補全指定位數。下面程式碼生成 10 位的數值字串。

'1'.padStart(10, '0') // "0000000001"
'12'.padStart(10, '0') // "0000000012"
'123456'.padStart(10, '0') // "0000123456"
複製程式碼

另一個用途是提示字串格式。


'12'.padStart(10, 'YYYY-MM-DD') // "YYYY-MM-12"
'09-12'.padStart(10, 'YYYY-MM-DD') // "YYYY-09-12"
複製程式碼

6. class建立物件以及繼承

我們我們建立一個物件有一下幾種方法

  • 字面量方法
  • 工廠模式方法
  • 構造器方法
  • class建立一個物件
  • 這裡重點說一下class建立一個物件。 關鍵字class可以定義一個類,我們通過這個類可以建立一個物件。
    class Num{
        constructor(name){
            this.name = name
        }
        say(){
            console.log(`我是${this.name}`)
        }
    }
    
    
    let ra = new Num("小強")
    ra.say()        //我是小強
    複製程式碼

    也就是說我們可以直接通過一個類來直接new一個物件。
    注意:

    class 是關鍵字,後面緊跟類名,類名首字母大寫,採取的是大駝峰命名法則。類名之後是{}。
    在{}中,不能直接寫語句,只能寫方法,方法不需要使用關鍵字
    方法和方法之間沒有逗號。不是鍵值對

    下面就是我們在做專案的時候所必須的--繼承。
    根據需求的不同我們所需要的物件的屬性或者方法也可能不同,或者多點屬性或者方法,難道我們需要將之前所寫的屬性在重新寫一次嗎?如果需要100個物件,每一個物件都多一個屬性或者方法呢?這時候我們就用到了--繼承,讓子類繼承父類的方法和屬性的同時還可以有自己的屬性和方法。這也是我們現在最常用的建立物件的方式。

    繼承

    格式:

    玩轉ES6新特性

    下面使用一個小案例,更進一步的瞭解一下。
    定義一個NBAplayer類,然後讓mvp這個類繼承NBAplayer,可以可以使用父類的方法

    
        class NBAplayer{
            constructor(name,age,height){
                this.name = name
                this.age = age
                this.height = height
    
            }
            say(){
                alert(`姓名${this.name}年齡${this.age}身高${this.height}`)
            }
            static jump(){   //靜態方法    只能使用類名去掉用。
                alert("我是靜態函式。。。。。物件無法呼叫")
            }
        }
        
    
    
        class mvp extends NBAplayer{
            constructor(name,age,height,year){
                super(name,age,height)
                this.year = year
            }
            showmvp(){
                alert(`我是${this.year}年的mvp`)
            }
    
        }
    
        let r2 = new mvp("xiaong",15,5,2222)
        // r2.say();     //正常執行
        // r2.showmvp()  //正常執行
        // NBAplayer.jump()     //呼叫靜態函式。
        mvp.jump()   
    複製程式碼

    在繼承的時候有兩點要注意:

    1. 使用 extends 關鍵字來實現繼承
    2. 在子類中的構造器 constructor 中,必須要顯式呼叫父類的 super 方法,如果不呼叫,則 this 不可用

    7. 箭頭函式

    箭頭函式只是一個函式的簡寫,在做專案的時候這個可以很大程度降低程式碼量

    //沒有引數的時候
    function f(){console.log("....")} //寫為箭頭函式
    var f1 = () => {console.log("....")}
    
    var x = 10,y = 11;
    //有一個引數x
    var f2 = x => {console.log(x+x)}
    
    //有兩個引數及以上的時候必須加括號
    var f3 = (x,y) => {console.log(x+y)}
    
    f1()      //.......
    f2(x)      //20
    f3(x,y)    //21
    複製程式碼

    要注意的是使用箭頭函式的時候不能使用this,這兩個老死不相往來。

    8. Set 和 Map

    Set

    set和陣列差不多但不是陣列,它是一種集合,它和陣列的區別在於:set裡面的值都是唯一的,沒有重複的。 看下面一段程式碼:在放入基本資料型別的時候需要使用[]包起來

    let arr = [1,1,1,2,5,5,6,9]
    let s1 = new Set([1,1,1,2,5,5,6,9])
    console.log(arr)  //[ 1, 1, 1, 2, 5, 5, 6, 9 ]
    console.log(s1)  //Set { 1, 2, 5, 6, 9 }
    console.log(Array.isArray(s1))  //false
    
    複製程式碼

    上面的程式碼我們很容易的看出來Set不是陣列,只是一個類陣列,那麼我們可以使用之前的知識將其轉化為陣列

    let r2 = [...s1]
    console.log(r2)    //[ 1, 2, 5, 6, 9 ]
    console.log(Array.isArray(r2))  //true
    複製程式碼

    在建立set的時候如果要放入物件需要使用add()方法

    let s1 = new Set();
    s1.add({name:"ddd"})
    s1.add({age:15})
    s1.add({year:2018})
    for(let item of s1){
        console.log(item)
    }
    複製程式碼

    根據set裡面資料的唯一性可以做一個小的案例---陣列

    let arr = [1,2,5,45,9,NaN,true,NaN]
    let rs = [...(new Set(arr))]
    console.log(rs)    //[ 1, 2, 5, 45, 9, NaN, true ]
    
    複製程式碼

    Map

    它類似於物件,裡面存放也是鍵值對,區別在於:物件中的鍵名只能是字串,但是使用map,它裡面的鍵可以是任意值。

    建立一個Map

    let m = new Map([
    ["name","xiaoming"],
    ["age","16"]
    ])
    m.set(false,"sss")
    m.set([],"a")
    console.log(m)     //Map { 'name' => 'xiaoming', 'age' => '16', false => 'sss', [] => 'a' }
    
    複製程式碼

    那麼很好理解Map是一個強大的類陣列,我們可以通過擴充套件運算子將其轉換為陣列,然後進行資料的處理等等。 Set和Map都可以轉換為陣列,需要注意的是它們的各自的新增元素的方法。

     

     

    ES6的特性還有很多,這裡只是簡單的介紹了幾種我們比較常見的,如果大家在開發的過程中有什麼新的東西,多多留言.

    相關文章