1. 程式人生 > >ES5和ES6那些你必須知道的事兒(三)

ES5和ES6那些你必須知道的事兒(三)

ES5和ES6那些你必須知道的事兒

ES6新增的東西

一、塊級作用域:關鍵字let,常量const

二、物件字面量屬性賦值簡寫

var name = “我是name”;
var age = 18var obj = {
    name,
    age      
}

//此處的物件的key值與value值是一樣的,所以簡寫

//不簡寫的話就是

var obj = {
    name:name,    //即name:“我是name”
    age:age     //即age:18
}

 

三、解構賦值

let singer = { first: "Bob", last: "Dylan" };
let { first: f, last: l } 
= singer; // 相當於 f = "Bob", l = "Dylan" let [all, year, month, day] = /^(\d\d\d\d)-(\d\d)-(\d\d)$/.exec("2015-10-25"); let [x, y] = [1, 2, 3]; // x = 1, y = 2

 

四、展開運算子... 

var arr=[1,2,3,4];

console.log(...arr)

//打印出來不是一個數組,
//而是將數組裡的內容分開列印
//1 2 3 4

 

五、箭頭函式

//正常函式的寫法:

function a(){
    
//內容 } //如果改成箭頭函式 a()=>{ //內容 }
//箭頭函式的簡寫

x => x * x

//上面的程式碼相當於下面的程式碼

function (x) {
    return x * x;
}

//如果引數不是一個,就需要用括號()括起來:

// 兩個引數:
(x, y) => x * x + y * y

// 無引數:
() => 3.14

// 可變引數:
(x, y, ...rest) => {
    var i, sum = x + y;
    for (i=0; i<rest.length; i++) {
        sum 
+= rest[i]; } return sum; } //如果要返回一個物件,就要注意,寫成下面這樣 x => ({ foo: x })

要注意箭頭函式的this

 

普通函式下的this:

  • 在普通函式中的this總是代表它的直接呼叫者,在預設情況下,this指的是window,
  • 在嚴格模式下,沒有直接呼叫者的函式中的this是 undefined使用
  • call,apply,bind(ES5新增)繫結的,this指的是 繫結的物件

箭頭函式中的this:

  •  箭頭函式沒有自己的this, 它的this是繼承而來; 預設指向在定義它時所處的物件(宿主物件),
  •  而不是執行時的物件, 定義它的時候,可能環境是window,也有可能是其他的。

 

看下面這段程式碼:

function a() { 
   console.log(this);  //window
 }  
 a(); 

因為a是一個全域性函式,也就是掛載在window物件下的,所以a(),等價於window.a();

 

var obj = {  
   say: function () {  
     setTimeout(function () {  
       console.log(this);   //window   
     });  
   }  
 }   
 obj.say(); 

定時器中的函式,由於沒有預設的宿主物件,所以this指向window

 

var obj = {  
   func: function() {},  
   say: function () {  
     console.log(this);//obj,此時的this是obj物件    
     setTimeout(function () {   
       console.log(this);  //window
       that.func();  
     });   
   }  
 }  
 obj.say(); 

此時say的宿主環境是obj,所以say裡面的this是obj,定時器中的函式, 由於沒有預設的宿主物件,所以預設this指向window

 

箭頭函式中的this:

var obj = {  
   say: function () {  
     setTimeout(() => {  
       console.log(this);// obj    
     });  
   }  
 }  
 obj.say(); 

此時的 this繼承自obj, 指的是定義它的物件obj, 而不是 window!

 

var obj = {  
say: function () {  
  var f1 = () => {  
    console.log(this); // obj  
    setTimeout(() => {  
      console.log(this); // obj  
    })  
  }  
  f1();  
  }  
}   
obj.say()
因為f1定義時所處的函式 中的 this是指的 obj, setTimeout中的箭頭函式this繼承自f1,所以不管有多層巢狀,都是 obj


var obj = {  
say: function () {  
  var f1 = function () {  
    console.log(this); // window, f1呼叫時,沒有宿主物件,預設是window  
    setTimeout(() => {  
      console.log(this); // window  
    })  
  };  
  f1();  
  }  
}  
obj.say() 

結果: 都是 window,因為 箭頭函式在定義的時候它所處的環境相當於是window, 所以在箭頭函式內部的this函式window

換個理解方式:因為箭頭函式沒有this,當需要判斷當前this是什麼的時候,把箭頭函式去掉,看剩下的程式碼此處的this指向哪裡即可。

 

六、字串模版` `

var name = "Bob", time = "today";
`Hello ${name}, how are you ${time}?`
// return "Hello Bob, how are you today?"

 

七、迭代器

 

八、生成器

 

九、class

Class,有constructor、extends、super,但本質上是語法糖(對語言的功能並沒有影響,但是更方便程式設計師使用)。

class Artist {
    constructor(name) {
        this.name = name;
    }

    perform() {
        return this.name + " performs ";
    }
}

class Singer extends Artist {

    constructor(name, song) {
        super.constructor(name);
        this.song = song;
    }

    perform() {
        return super.perform() + "[" + this.song + "]";
    }
}

let james = new Singer("Etta James", "At last");
james instanceof Artist; // true
james instanceof Singer; // true

james.perform(); // "Etta James performs [At last]"

 

十一、Map() Set()

// Sets
var s = new Set();
s.add("hello").add("goodbye").add("hello");
s.size === 2;
s.has("hello") === true;

// Maps
var m = new Map();
m.set("hello", 42);
m.set(s, 34);
m.get(s) == 34;

 

十二、一些新的API

 

一些新的API

Number.EPSILON
Number.isInteger(Infinity) // false
Number.isNaN("NaN") // false

Math.acosh(3) // 1.762747174039086
Math.hypot(3, 4) // 5
Math.imul(Math.pow(2, 32) - 1, Math.pow(2, 32) - 2) // 2

"abcde".includes("cd") // true
"abc".repeat(3) // "abcabcabc"

Array.from(document.querySelectorAll('*')) // Returns a real Array
Array.of(1, 2, 3) // Similar to new Array(...), but without special one-arg behavior

[0, 0, 0].fill(7, 1) // [0,7,7]
[1, 2, 3].find(x => x == 3) // 3
[1, 2, 3].findIndex(x => x == 2) // 1
[1, 2, 3, 4, 5].copyWithin(3, 0) // [1, 2, 3, 1, 2]
["a", "b", "c"].entries() // iterator [0, "a"], [1,"b"], [2,"c"]
["a", "b", "c"].keys() // iterator 0, 1, 2
["a", "b", "c"].values() // iterator "a", "b", "c"

Object.assign(Point, { origin: new Point(0,0) })

 

 

十三、proxy

Proxy 讓我們能夠以簡潔易懂的方式控制外部對物件的訪問。其功能非常類似於設計模式中的代理模式。

 

使用 Proxy 的好處是:物件只需關注於核心邏輯,一些非核心的邏輯(如:讀取或設定物件的某些屬性前記錄日誌;設定物件的某些屬性值前,需要驗證;某些屬性的訪問控制等)可以讓 Proxy 來做。從而達到關注點分離,降級物件複雜度的目的。

 

var p = new Proxy(target, handler);

 

其中,target 為被代理物件。handler 是一個物件,其聲明瞭代理 target 的一些操作。p 是代理後的物件。

 

當外界每次對 p 進行操作時,就會執行 handler 物件上的一些方法。handler 能代理的一些常用的方法如下:

 

  • get:讀取
  • set:修改
  • has:判斷物件是否有該屬性
  • construct:建構函式
  • ...

 

var target = {
   name: 'obj'
 };
 var logHandler = {
   get: function(target, key) {
     console.log(`${key} 被讀取`);
     return target[key];
   },
   set: function(target, key, value) {
     console.log(`${key} 被設定為 ${value}`);
     target[key] = value;
   }
 }
 var targetWithLog = new Proxy(target, logHandler);
 targetWithLog.name; // 控制檯輸出:name 被讀取,執行的get
 targetWithLog.name = 'others'; // 控制檯輸出:name 被設定為 others,執行了set
console.log(target.name); // 控制檯輸出: others
  • targetWithLog 讀取屬性的值時,實際上執行的是 logHandler.get :在控制檯輸出資訊,並且讀取被代理物件 target 的屬性。
  • 在 targetWithLog 設定屬性值時,實際上執行的是 logHandler.set :在控制檯輸出資訊,並且設定被代理物件 target 的屬性的值。
實現私有變數   代理中把以  _ 開頭的變數都認為是私有的。
var api = {
  _secret: 'xxxx',
  _otherSec: 'bbb',
  ver: 'v0.0.1'
};

api = new Proxy(api, {
  get: function(target, key) {
    // 以 _ 下劃線開頭的都認為是 私有的
    if (key.startsWith('_')) {
      console.log('私有變數不能被訪問');
      return false;
    }
    return target[key];
  },
  set: function(target, key, value) {
    if (key.startsWith('_')) {
      console.log('私有變數不能被修改');
      return false;
    }
    target[key] = value;
  },
  has: function(target, key) {
    return key.startsWith('_') ? false : (key in target);
  }
});

api._secret; // 私有變數不能被訪問
console.log(api.ver); // v0.0.1
api._otherSec = 3; // 私有變數不能被修改
console.log('_secret' in api); //false
console.log('ver' in api); //true

 

使用代理(Proxy)監聽物件的操作,然後可以做一些相應事情。

可監聽的操作: get、set、has、deleteProperty、apply、construct、getOwnPropertyDescriptor、defineProperty、getPrototypeOf、setPrototypeOf、enumerate、ownKeys、preventExtensions、isExtensible。

 

十四、Symbol

Symbol是一種基本型別。Symbol 通過呼叫symbol函式產生,它接收一個可選的名字引數,該函式返回的symbol是唯一的。

var key = Symbol("key");
var key2 = Symbol("key");
key == key2  //false

 

十五、promise

Promises是處理非同步操作的物件,使用了 Promise 物件之後可以用一種鏈式呼叫的方式來組織程式碼,讓程式碼更加直觀

function fakeAjax(url) {
  return new Promise(function (resolve, reject) {
    // setTimeouts are for effect, typically we would handle XHR
    if (!url) {
      return setTimeout(reject, 1000);
    }
    return setTimeout(resolve, 1000);
  });
}

// no url, promise rejected
fakeAjax().then(function () {
  console.log('success');
},function () {
  console.log('fail');
});

非同步操作的同步程式碼