帶你一起敲敲ES6的新特性,邊解釋邊應用!

xlei1123發表於2019-03-04

一,變數宣告

像在es4中,使用var宣告的變數存在變數提升,下面這樣是不會報錯的。但是在es6中使用的const和let不行,會報錯!!

console.log(a);
var a = 5;
複製程式碼
  1. 常量(const,不會變數提升,塊級作用域,作用域內值不能改)
  2. 塊級作用域(let,不會變數提升)
for (let i = 0; i<5; i++) {
  setTimeout(() => {
    console.log(i)    //0 1 2 3 4
  },30)
}
for (var i = 0; i<5; i++) {
  setTimeout(() => {
    console.log(i)   //5 5 5 5 5
  },30)
}
複製程式碼

特別要說明一點的是 對於const和let都有暫存死區,所謂暫存死區就是:
如果作用域內 有這樣一個變數 那麼這個作用域內就會繫結這個變數,不會繼續向上查詢了,以下程式碼執行會報錯。

const a = 1;
{

  console.log(a);
  const a = 2;
}
console.log(a)
複製程式碼

二,解構賦值

所謂解構賦值就是 宣告和賦值都放到了一起 一般都是陣列 對 陣列, 物件 對 物件, 陣列能夠設定預設值,物件也能夠設定預設值,預設值必須採用等號的方式

let [zhan, si, xl = 5] = [3, 4];
console.log(zhan, si, xl) //3, 4, 5

let {name, age = 23} = {name: `xl`, bigAge: 24}
console.log(name, age) //xl, 23
複製程式碼

特別的,可能有時會有關鍵字的情況可以通過:的形式來更改名字,看下面程式碼:

let { name, age: xl, default: d } = { name: `xlei`, age: 9, default: `xxx` };
console.log(name, xl, d);
複製程式碼

來一個預設值的具體應用吧:

function ajax({
    url = new Error(`url without`),
    type = `get`,
    data = xxx
}){
  console.log(data, type)   //{a: 5}, get
}
ajax({
    url: `/test`,
    data: {a:5}
})
複製程式碼

三,字串

  1. 模板字串(拼接方便,可以換行)
let exe1 = xlei
let exe2 = `${exe1}nihao
我也好`
複製程式碼
  1. startWith, endWith 返回一個布林值
let str1 = `www.bsym.online`
let str2 = `http://www.bsym.online`
console.log(str1.startsWith(`http://`))   //false
console.log(str2.startsWith(`http://`))   //true
console.log(str2.endsWith(`online`))     //true
複製程式碼
  1. padStart, padEnd補全 — 不會刪除原有內容
// padStart padEnd 補全(記住只能增加,不能減少)
let str1 = `nihao`
let newStr = str1.padStart(8,`xl`)
let newStr2 = str1.padEnd(8,`xl`)
console.log(newStr, newStr2)   //xlxnihao, nihaoxlx
複製程式碼

四,箭頭函式(解決this問題,書寫起來也更簡單)

傳統函式內的this是定義時所在的環境,而箭頭函式內的this是使用時上下文的環境。

let aa = (arg1, arg2) => {
  console.log(arg1, arg2)
}

aa(1, 2)   //1, 2

;((arg1, arg2) => {
  console.log(arg1, arg2)
})(3, 4);
複製程式碼

這裡順帶提一下,像上面的自執行匿名函式前後都要加分號,這樣既不會被坑,也不會坑別人。另外不要使用箭頭函式的argeuments

五,擴充套件運算子

  1. 陣列的擴充套件運算子:將一個陣列轉為用逗號分隔的引數序列
let arr = [...[1, 2, 3], ...[4, 5, 6]]
console.log(arr)   // 1, 2, 3, 4, 5, 6
console.log(Math.min(...arr))  // 1
複製程式碼
  1. 物件的解構賦值

物件的 Rest 解構賦值用於從一個物件取值,相當於將所有可遍歷的、但尚未被讀取的屬性,分配到指定的物件上面,注意Rest 解構賦值必須是最後一個引數,否則會報錯。Rest解構賦值所在的物件,拷貝了物件obj的屬性,Rest解構賦值的拷貝是淺拷貝,即如果一個鍵的值是複合型別的值(陣列、物件、函式)、那麼Rest解構賦值拷貝的是這個值的引用,而不是這個值的副本,解構賦值不會拷貝繼承自原型物件的屬性

let obj = {name: `xl`, age: 23, say:`ok`, eat: {xl: `okok`}}
let {name, age, ...z} = obj    //尚未被讀取的屬性,分配到指定的物件上面,淺拷貝了物件obj的屬性
obj.say = `oo`
obj.eat.xl = `o?o?`
console.log(name, age, z)  //xl 23 { say: `ok`, eat: { xl: `o?o?` } }
複製程式碼
let z = {a: 3, b: 4, c:{
    eat:`ok`
}}
let n = {...z}   注意這個地方和直接賦值的區別 let n = z; 一個是淺拷貝物件屬性,一個是淺拷貝物件
z.a = 5
z.c.eat = `ok?`
console.log(n)  //{ a: 3, b: 4, c: { eat: `ok?` } }
複製程式碼

那麼要是想實現一個深拷貝,怎麼實現呢?其實就是遍歷屬性如果屬性是一個普通值就賦值,不是普通值就遞迴知道是普通值為止,然後賦值,程式碼如下:

// 實現深拷貝 保留繼承關係 可以實現各種型別的拷貝 實現遞迴拷貝
    function deepClone(obj) {
        if (typeof obj !== `object`) return obj;
        if (obj == null) return null;
        if (obj instanceof Date) return new Date(obj);
        if (obj instanceof RegExp) return new RegExp(obj);
        let o = new obj.constructor(); // 保留類的繼承關係
        // for (let key in obj) {
        //     // console.log(obj.hasOwnProperty === Object.prototype.hasOwnProperty) 
        //     if ( obj.hasOwnProperty(key) ) {   //只有自身屬性才賦值
        //         if(typeof (obj[key]) == `object`){
        //             o[key] = deepClone(obj[key])
        //         }else{
        //             // console.log(obj[key])
        //             o[key] = obj[key]
        //         }
                
        //     }
        // }
        Object.keys(obj).forEach((key, index) => {
            if(typeof (obj[key]) == `object`){
                o[key] = deepClone(obj[key])
            }else{
                // console.log(obj[key])
                o[key] = obj[key]
            }
        })
        return o;
    }
    let o = { a: { a: 1 }, b: function(){
        console.log(this.a)
    } }
    let newObj = deepClone(o);
    o.a.a = 2;
    console.log( newObj.b());
複製程式碼

六,陣列常用方法

// 1)map返回值 返回值是一個新陣列
    Array.prototype.map = function (fn) {
        let arr = [];
        for (let i = 0; i < this.length; i++) {
            arr.push(fn(this[i], i));
        }
        return arr;
    };
    let arr = [1, 2, 3].map(item => {
        return item * 2;
    });
    console.log(arr);
    // 2)filter 過濾 如果返回true表示留下 返回false表示刪除
    let arr = [1, 2, 3];
    let filterArr = arr.filter(item => {
        return item > 2;
    });
    console.log(filterArr);
    // 3)some找到後返回true,找false可以用every 
    let r = [2, 1, 3].some(item => {
        return item > 2;
    });
    console.log(r);  //true
    // 4)every 檢測陣列 ages 的所有元素是否都符合條件 :

    var ages = [2, 1, 3];

    let r = ages.every((item) => {
        return item > 2
    })
    console.log(r)  //false
    // 5)Array.from();   將類陣列轉為陣列
複製程式碼

七,es6的class

先複習一下es5中的幾個名詞:

  1. 成員屬性(方法)| 例項屬性(方法) :在建構函式中通過this.屬性宣告的
  2. 靜態屬性(方法):通過類來宣告的 類.xxx
  3. 私有屬性(方法):只有在類的內部可以使用,其他任何地方都不可以使用的
  4. 公有屬性(方法)|原型屬性(方法):在原型上宣告的屬性或者方法 xx.prototype.xxx
    敲程式碼:
function Parent(name) {
    this.name = name; //成員屬性|例項屬性
    this.say = function() {   //成員方法
        console.log(this.name)
    }
}
Parent.smoking = `no`   //靜態屬性
Parent.prototype.up = function() {   //公有方法|原型方法
    console.log(`ok`)
}
複製程式碼

再來說說es6中的class(es6中不考慮私有屬性和方法):

class Parent{
    constructor(x, y){
        this.x = x;      //成員屬性|例項屬性  可遍歷 列印例項可直接列印出來, // 與 ES5 一樣,例項的屬性除非顯式定義在其本身(即定義在this物件上),否則都是定義在原型上(即定義在class上)。
        this.y = y;
        return this.x     //如果不返回 預設返回例項物件 this
    }
    static b(){ // 屬於類上的方法 也稱靜態方法
        return 2;
    }
    eat(){    //原型上的方法 | 公有方法 並且都是不可列舉的 列印例項不能顯示的列印出來 
        console.log(this.x);
        return this.x
    }
    // Object.assign(Parent.prototype, {
        // eat(){},
    // });
}
class Child extends Parent{ // 
    constructor(x, y, z){
        super(x, y); // Parent.call(this);     返回的是子類的例項,
        this.age = z; // 成員屬性|例項屬性
    }
    static a(){ // 屬於類上的方法
        return 1;
    }
    smoking(){ // 原型上的方法
        return super.eat() + this.age    //需要說明的是 super不僅可以呼叫父類的原型方法還可以呼叫父類的靜態方法,方法內部的this指向當前的子類,而不是子類的例項
        // console.log(this.age)
        
    }
}
let child = new Child(2, 3, 4);
// console.log(child);
console.log(child.smoking())

class Foo {
    constructor() {  //constructor函式預設返回this, 這裡返回一個全新的物件,結果導致例項物件不是Foo類的例項
        return Object.create(null);
    }
}

new Foo() instanceof Foo
// false

//定義類
class Point {

    constructor(x, y) {
        this.x = x;        
        this.y = y;
    }

    toString() {
    return `(` + this.x + `, ` + this.y + `)`;
    }

}

var point = new Point(2, 3);
console.log(point)
point.toString() // (2, 3)

point.hasOwnProperty(`x`) // true
point.hasOwnProperty(`y`) // true
point.hasOwnProperty(`toString`) // false
point.__proto__.hasOwnProperty(`toString`) // true


class A {
}

class B extends A {
}

B.__proto__ === A // true
B.prototype.__proto__ === A.prototype // true
複製程式碼

以上就是ES6常用的幾個新特性,動手敲一遍,你就記住了!當然以上肯定會存在很多不足的地方,歡迎各位提出寶貴的意見或建議,也希望能幫助到你從中獲得一些知識!

相關文章