es6--let const 生成器 yield Symbol 箭頭函數(shù) SpreadJS Map/WeakMap Set/WeakSet Promise Proxy

  • let and const
  • Destructuring 解構(gòu)賦值
  • Spread and Reset SpreadJS擴展語句
  • Arrow Functions 箭頭函數(shù)
  • Template Literals 模板字符串 ``
  • Classes 類 繼承
  • Symbols es6第七種數(shù)據(jù)類型
  • Iterators 迭代器
  • Generators 生成器
  • Promises
  • Map 與Object對比
  • WeakMaps
  • Sets
  • WeakSets
  • Proxy 代理講解+實例
es6

es6英文網(wǎng)站:https://nodejs.org/en/docs/es6/

babel英文網(wǎng)站 (將es6轉(zhuǎn)換為es5) https://babeljs.io/

一、 let 、 const

  • let 變量 只在本作用域中

    • function letTest() {
          let foo = true;
          if(true) {
              let foo = false;  //只在本級block-->{}中有效
              console.log(foo); //false
          }
          console.log(foo);  //true
      }
      letTest();
      // console.log(foo);  //未定義 報錯
      
    • if else語句中var變量在條件語句外仍然有效

      function varTest() {
          var foo = true;
          if(true) {
              var foo = false;
              console.log(foo); //false 沒毛病
          }
          console.log(foo);  //false 因為if里的var聲明會被提到外面
      }
      varTest();
      console.log(foo); //外部未定義,報錯
      
  • {里面是一塊區(qū)域 block}

  • es6中避免使用var

const

  • 不能修改聲明的基本數(shù)據(jù)類型的值(number string boolean undefined
    null)

    const str = 'ab';  
                str = 'bc';  
                console.log(str);// Uncaught TypeError: Assignment to constant variable. 
               //其他四種同樣報錯
    
  • 可以修改引用類型的引用

    //引用類型保存在內(nèi)存中,js不允許直接訪問內(nèi)存,so在操作的時候,其實是修改的是對象的引用 
    //例如:object:
    const foo = {
    one:'hello',
    two:{
        three:'Goodbye'
        };
    };
    foo.name='world';  //增加name
    foo.two.three='not goodbye';  //修改foo.two.three里的內(nèi)容
    console.log(foo);
    
    //其他引用類型 Array Function 同objext可修改增加
    

二、SpreadJS 擴展語句

https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators/Spread_syntax

  • 解構(gòu)賦值
    var arr = [1,2,3,4,5];
    var [a,b,c,d,e] = arr;
    console.log(a);  //1
    
  • ...+數(shù)組名
let arr = [1,2,3,4];
console.log(...arr);   //1,2,3,4
```
var meats = ['bacon','ham'];
var food = ['apple',...meats,'kiwi','rice'];
console.log(food)  //[ 'apple', 'backon', 'ham', 'kiwi', 'rice' ]
```

```
function addNum(a,b,c) {
    console.log(a+b+c);
}
var num = [1,2,3];
addNum(num[0],num[1],num[2]);
addNum(...num);  //6
```

三、箭頭函數(shù) Arrow Function

  • 引入箭頭函數(shù)有兩個方面作用:更簡短的函數(shù) + 不綁定this

  •   var materials = [
      'Hydrogen',
      'Helium',
      'Lithium',
      'Beryllium'
    ];
    
    materials.map(function(material) { 
      return material.length;  //字符串長度
    }); // [8, 6, 7, 9]
    
    materials.map((material) => {
      return material.length;
    }); // [8, 6, 7, 9]
    
    materials.map(material => material.length); // [8, 6, 7, 9]
    
  • let circleArea3 = r=> 3.14 * r * r  
    console.log(circleArea3(7));
    
  • 討厭的this 箭頭函數(shù)出現(xiàn)之前

    function Person() {
      // Person() 構(gòu)造函數(shù)定義 `this`作為它自己的實例.
      this.age = 0;
    
      setInterval(function growUp() {
        // 在非嚴格模式, growUp()函數(shù)定義 `this`作為全局對象, 
        // 與在 Person()構(gòu)造函數(shù)中定義的 `this`并不相同.
        this.age++;  //這個其實等同于window.age++,和Person里的this.age沒有半毛關(guān)系
      }, 1000);
    }
    
    var p = new Person();
    
  • 在ECMAScript 3/5中,通過將this值分配給封閉的變量,解決this指向問題

    function Person() {
      var that = this;
      that.age = 0;
    
      setInterval(function growUp() {
        //  回調(diào)引用的是`that`變量, 其值是預(yù)期的對象. 
        that.age++;這個就是Person里的age,不再是指windo.age的
      }, 1000);
    }
    
  • 箭頭函數(shù)里不會創(chuàng)建自己的this,它就是使用封閉執(zhí)行上下文綁定的this值,

    • so,下面代碼傳遞給setInterval的函數(shù)(構(gòu)造函數(shù)Person)內(nèi)的this與封閉函數(shù)中的this值相同
    function Person(){
      this.age = 0;
    
      setInterval(() => {
        this.age++; // |this| 正確地指向person 對象
      }, 1000);
    }
    
    var p = new Person();
    

四、模板字符串直接輸出變量 ${變量名}

  • 空格不折疊
let name ='apple';
 console.log(`我最愛的水果是 ${name}因為酸甜`);
 
 
 console.log("我最愛的水果是:"+ name +'因為' +
    '好吃');                 //輸出不會換行,拼接字符串空格折疊
    //我最愛的水果是蘋果因為好吃
 console.log(`我最愛的是 ${name}因
     為好吃`);                     //輸出會換行
     //我最愛的是apple因      
     //為好吃                       

五、class類--constructor、 super 、 extends

 class Person {           //父類 
    constructor(name, age, weight) {
        this.name = name;
        this.age = age;
        this.weight = weight;
    }
    displayName() {
        console.log(this.name);
    }
    displayAge() {
        console.log(this.age);
    }
    displayWeight() {
        console.log(this.weight);
    }
}

class Programmer extends Person{   //繼承父類
    constructor(name, age, weight,language) {
      super(name,age,weight);   //constructor里會先繼承父類的super
      this.language = language; 
    }
    displayLanguage() {
        console.log(this.language);
    }
}
let sally = new Person('sally',21,49);
sally.displayName();
sally.displayAge();
sally.displayWeight();
console.log('---------------');
let bucky = new Programmer('bucky roberts',87,987,'javascript');
bucky.displayName();
bucky.displayAge();
bucky.displayLanguage();   //Programmer子類特有的,Person沒有

六、Symbol

  • 復習:JavaScript
    • 5種基本數(shù)據(jù)類型--number string boolean undefined null +
    • 1種復雜數(shù)據(jù)類型 -- Object
  • es6添加了一種原始數(shù)據(jù)類型 : Symbol
  • Symbol()不等于任何值,不能與其他任何類型的值進行運算,
```
let sym = Symbol('foo');
console.log(sym);   //Symbol(foo)
console.log(typeof sym);   //symbol
console.log(Symbol('foo') ===Symbol('foo'));  //false
console.log(Number(3) ===Number(3));  //true
```
  • symbol不能被自動轉(zhuǎn)換為字符串,嘗試拼接symbol與字符串將得到TypeError錯誤

    var s1 = Symbol("hello");
    console.log(`輸出的s1是:${s1}`);  //報錯
    var s2 = s1.toString(); //或者 var s2 = String(s1); 
    console.log(`輸出的s1是:${s2}`);  //輸出的s1是 Symbol(hello)
    
  • 具體應(yīng)用英文: http://www.zsoltnagy.eu/es6-symbols-and-its-use-cases/

七、JavaScript迭代器 函數(shù)生成器

有幾個特點:

  • 1、函數(shù)名前面有一個‘*’
      2、通過調(diào)用該函數(shù)生成一個控制器
      3、調(diào)用next()方法開始執(zhí)行函數(shù)
      4、碰到y(tǒng)ield,函數(shù)會暫停
      5、再次調(diào)用next(),繼續(xù)執(zhí)行函數(shù)

  • 生成器是function 用來控制迭代器

  • yield 關(guān)鍵字:它可以暫停函數(shù)的執(zhí)行,隨后可以再進進入函數(shù)繼續(xù)執(zhí)行

  • 太抽象,舉例子:

  • for循環(huán)中就是簡簡單單的把輸出的變量一次性輸出

    for (let i = 0; i < 5; i += 1) {
      console.log(i);
    }
    // 直接輸出所有的  0 -> 1 -> 2 -> 3 -> 4
    
  • 現(xiàn)在迭代生成器函數(shù) .next()

  • function * generatorForLoop(num) {
      for (let i = 0; i < num; i += 1) {
        yield console.log(i);
      }
    }
    
    const genForLoop = generatorForLoop(5);
    
    genForLoop.next(); // first console.log - 0
    genForLoop.next(); // 1 每調(diào)一次next,函數(shù)繼續(xù)向下執(zhí)行一次,
    genForLoop.next(); // 2
    genForLoop.next(); // 3
    genForLoop.next(); // 4
    

    我們每next一下,就獲取代碼運一步的結(jié)果,不會一次性把所有的都輸出

    • 除了.next()可以迭代生成器,for循環(huán)也可以獲取生成器變量的值
    function * generator(arr) {
      for (const el in arr)
        yield el;
    }
    
    const gen = generator([0, 1, 2]);
    
    for (const g of gen) {
      console.log(g); // 0 -> 1 -> 2
    }
    
    gen.next(); // {value: undefined, done: true}
    console.log(generator[0])  //undefined
    

    注意:for in循環(huán)在這里不起作用,而且變量的獲取也不能通過generator[0]這種方法獲得

    • 如何創(chuàng)建生成器
    function * generator () {}
    function* generator () {}
    function *generator () {}
    
    let generator = function * () {}
    let generator = function* () {}
    let generator = function *() {}
    
    let generator = *() => {} // SyntaxError 報錯
    let generator = ()* => {} // SyntaxError 報錯
    let generator = (*) => {} // SyntaxError 報錯
    
    • ==上面可以看出,生成器的構(gòu)建不能通過箭頭函數(shù)的方式==

    下面的生成器的例子用作方法,聲明方式與function一致

    class MyClass {
      *generator() {}
      * generator() {}
    }
    
    const obj = {
      *generator() {}
      * generator() {}
    }
    
    • ==生成器函數(shù)創(chuàng)建必須初始化==
    function * generator(arg = 'Nothing') {
      yield arg;
    }
    
    const gen0 = generator(); // 沒毛病
    const gen1 = generator('Hello'); // 也沒毛病
    const gen2 = new generator(); // 沒有初始化,會報錯
    
    generator().next(); // 這可以有用,但每次都從頭開始
    

八、Yield

  • 函數(shù)中的return :意味著函數(shù)里return后面的所有都不會再執(zhí)行到

    function withReturn(a) {
      let b = 5;
      return a + b;  //到這里就跳出這個函數(shù)了
      b = 6; // 我們永遠都不會到這一步,再改變b
      return a * b; // 當然更不會走到這一步了
    }
    
    withReturn(6); // 11
    withReturn(6); // 11
    
    • Yield不同
    function * withYield(a) {    //生成器函數(shù)
      let b = 5;
      yield a + b;
      b = 6; // it will be re-assigned after first execution
      yield a * b;
    }
    
    const calcSix = withYield(6);
    
    calcSix.next().value; // 11
    calcSix.next().value; // 36
    
  • 解釋 yeild一次返回一個值,下一次你再調(diào)同一個函數(shù)的時候,會在上一次yield值后繼續(xù)進行下去

  • 在生成器中next()方法返回一個對象,這個對象包含兩個屬性:

    • value 和 done,value 屬性表示本次 yield 表達式的返回值,done 屬性為布爾類型,表示生成器后續(xù)是否還有 yield 語句,即生成器函數(shù)是否已經(jīng)執(zhí)行完畢并返回
    • 執(zhí)行完畢即當在生成器函數(shù)中顯式 return 時會導致生成器立即變?yōu)橥瓿蔂顟B(tài),即調(diào)用 next() 方法返回的對象的 done 為 true,
function* simpleGenerator(){
    yield 'apples';  //到這一步,停一次
    yield 'bacon';  //再停一次
    console.log('ok,this is the line after the bacon');
    yield 'corn';   //再停一次
}
let simple = simpleGenerator();
console.log(simple.next());    //{ value: 'apples', done: false }
console.log(simple.next().value);  //bacon .value只要值,
console.log(simple.next().value);  //ok,this is the line after the bacon +// corn
console.log(simple.next().value);  //結(jié)束了,沒有了,再想有next就是undefined
  • 其實在生成器中,不僅yield可以使用,return也可以,只不過一旦遇到return后面的就都不會執(zhí)行,直接跳出該函數(shù)了

  • function * generator() {
      yield 1;   //停一次
      return 2;   //跳出生成器函數(shù),后面的不會執(zhí)行
      yield 3; // 永遠到不了這一步了
    }
    
    const gen = generator();
    
    gen.next(); // {value: 1, done: false}
    gen.next(); // {value: 2, done: true}
    gen.next(); // {value: undefined, done: true} 
    
    • yield委托
      yield * 可以在另一個生成器中起作用,這樣可以一直鏈接無數(shù)個生成器
    function * anotherGenerator(i) {
      yield i + 1;
      yield i + 2;
      yield i + 3;
    }
    
    function * generator(i) {
    yield i;  //第一步輸出 10
      yield* anotherGenerator(i);  //到anotherGenerator里 分別停11 12 13
      yield i+10;  //回到i +20 停一次 
    }
    
    var gen = generator(10);
    
    console.log(gen.next().value); // 10
    console.log(gen.next().value); // 11
    console.log(gen.next().value); // 12
    console.log(gen.next().value); // 13
    console.log(gen.next().value); // 20
    console.log(gen.next().value); // undefined
    console.log(gen.next().value); // undefined
    console.log(gen.next().value); // undefined
    console.log(gen.next().value); // undefined
    
function* getNextId(){
    let id = 0;
    while(id < 3) {
        yield id++;                 //pauses
    }
}
let createUser = getNextId();  
console.log(createUser.next().value);   //0
console.log(createUser.next().value);   //1
console.log(createUser.next().value);  //2
console.log('hello world');    
console.log(createUser.next().value);   //undefined

九、Map

  • Map 對象保存鍵值對。任何值(對象或者原始值) 都可以作為一個鍵或一個值。

  • 鍵值對存儲,意味著每個map實例里的key都不會重復

  • 獲取值通過map.get(鍵名) ,通過map.size獲取Map里元素數(shù)量

  •    var myMap = new Map();
        console.log(typeof myMap); //object
         console.log(myMap.size);  //沒有set存進去鍵值對,size為0
    
        myMap.set('foo','bar');
        console.log(myMap.size);  //1
         myMap.set(12,'hh');  //鍵值對類型不受約束
        console.log(myMap.get('foo'));   //通過get獲取鍵值對的值
    
  • 詳細了解Map和以及其與Object的區(qū)別,點擊我這里

十、WeakMap

  • 不像Map有size屬性獲取元素數(shù)量,
  • 不能通過迭代forEach登遍歷元素
  • 最大區(qū)別:如果元素刪除/釋放,WeakMap就將該鍵值對從中刪除,不會再獲取到,因此這也是為什么WeakMap多用于聲明私有變量

Map和WeakMap的區(qū)別:

var myMap = new Map();
var myWeakMap = new WeakMap();

var obj1 = {'foo':'bar'};
var obj2 = {'bar':'baz'};
myMap.set(obj1,'hello');
myWeakMap.set(obj2,'hello');
console.log(myMap.get(obj1));  //hello
console.log(myWeakMap.get(obj2));  //hello
//存儲鍵值對和獲取的方法一致

Map WeakMap
key可以是任何數(shù)據(jù)類型 key鍵值是弱引用,所以必須是Object類型(除了null);值任意
Map有.size獲取元素數(shù)量 沒有.size屬性獲取數(shù)量
可用.forEach()方法遍歷 沒有 .foreach()方法
鍵值對不會自動銷毀 如果WeakMap里的key被刪除了,對應(yīng)的值也會被立馬銷毀垃圾回收
  • WeakMap中,每個鍵對自己所引用對象的引用是 "弱引用",===》 如果沒有其他引用和該鍵引用同一個對象,這個對象將會被當作垃圾回。

obj1 = null;
obj2 = null;
//map里元素不能主動刪除釋放
myMap.forEach(function (val,index) {
    console.log(index,val);   //{ foo: 'bar' } 'hello'
});

// myMap.forEach(function (val,index) {  //報錯,沒有該方法
//     console.log(index,val);
// });

console.log(myWeakMap.get(obj2));  //undefined  已經(jīng)垃圾回收了,


myMap.delete(obj1);
myMap.forEach(function (val,index) {
    console.log(index,val);   //{ foo: 'bar' } 'hello'
});

console.log(myMap.size);   //1
console.log(myWeakMap.size);  //undefined ,沒有該方法

十一、Set

  • Set對象允許你存儲任何類型的唯一值,無論是原始值或者是對象引用

  • .size獲取元素數(shù)量;

  • .add(某一元素值)添加元素

  • .delete(某一值)來刪除該元素

  • .has(某一值)判斷set中是否有該元素

  • var mySet = new Set();
    mySet.add(10);
    mySet.add('foo');
    mySet.add({'foo':'bar'});
    
    console.log(mySet.size);  //3
    mySet.delete('foo');
    console.log(mySet.size);   //2
    console.log(mySet.has(10));  //true
    
  • for遍歷Set里元素

  • for(let item of mySet) {
    console.log(item);  //10 -> foo -> { foo: 'bar' }
    }
    
    for(let item of mySet.keys()) {
        console.log(item);   //10 -> foo -> { foo: 'bar' }
    }
    
    for(let item of mySet.values()) {
        console.log(item);  //10 -> foo -> { foo: 'bar' }
    }
    for(let [key,value] of mySet.entries()) {  //key和value相等
        console.log(key); //10 -> foo -> { foo: 'bar' }
           console.logvalue); //10 -> foo -> { foo: 'bar' }
    }
    
  • 與數(shù)組Array相關(guān);存儲的樣式有點類似array

  • console.log(mySet);  //Set { 10, 'foo', { foo: 'bar' } }
    console.log([...mySet]);   //[ 10, 'foo', { foo: 'bar' } ]
    

十二、WeakSet

Weakset以及與Set區(qū)別

  • 僅僅是對象的集合,不像Set是任何類型的任意值

  • var mySet = new Set();
    var myWeakSet = new WeakSet();
    
    var obj1 ={};
    var obj2 = {};
    mySet.add(obj1);
    mySet.add(obj2);
    
    myWeakSet.add(obj1);
    myWeakSet.add(obj2);    //只能添加Object類型元素
    // myWeakSet.add(1);    //報錯
    
  • 沒有.size屬性獲取元素數(shù)量

  • console.log(mySet.size); //3
    console.log(myWeakSet.size);  //undefined
    
    
  • 可以通過.has判斷是否有某一元素

  • console.log(mySet.has(obj1));  //true
    console.log(myWeakSet.has(obj1));  //true
    
  • 對象集合是弱引用,如果沒有對應(yīng)的引用,就會被垃圾回收,這也意味著就不會再存儲列表里

  • console.log(mySet);  //Set { {}, {} }
    console.log(myWeakSet);  //WeakSet {}
    
  • 不能被枚舉

  • for(let item of mySet) {
        console.log(item)  //{} -> {} 依然存在
    }
    // for(let item of myWeakSet) {
    //     console.log(item)  //報錯, :myWeakSet is not iterable
    // }
    

十三、Proxy

計算機術(shù)語中,什么是Proxy代理:

在計算術(shù)語中,代理位于你和你正在通信的事物之間。這個術(shù)語通常應(yīng)用于代理服務(wù)器,它是一個介于web瀏覽器(Chrome、Firefox、Safari、Edge等)和web服務(wù)器(Apache、Nginx、IIS等)之間的設(shè)備。代理服務(wù)器可以修改請求和響應(yīng)。例如,它可以通過緩存定期訪問屬性并將其提供給多個用戶來提高效率。
在ES6中proxies就是位于你的代碼和object之間。它允許你執(zhí)行元編程操作,比如:攔截一個呼叫來檢查或變更對象的屬性。
  • Proxy對象用于為基本操作定義定制行為(如屬性查找、賦值、枚舉、函數(shù)調(diào)用等)。
  • 看似Proxy的相關(guān)專業(yè)詞匯很多,其實你只需要熟記幾個關(guān)鍵的:
    • handler -- 實現(xiàn)代理行為的對象

    • target -- 代理將虛擬化的原始對象。這可能是一個JavaScript的object對象,比如jQuery庫或本地對象如數(shù)組,甚至是另一個代理。

    • traps -- 處理程序中定義的函數(shù),當調(diào)用特定的屬性或方法時,它提供對目標的訪問。

  • 通俗講,Proxy代理是構(gòu)造函數(shù),返回Proxy對象,主要用于從外部控制對對象內(nèi)部的訪問
  • 舉個例子:我們創(chuàng)建target對象,有以下三個屬性:

  • const target = {
        a:1,
        b:2,
        c:3
    };
    
    
  • 創(chuàng)建handler對象攔截所有的get操作,如果target里有該屬性,就返回它,沒有就輸出數(shù)字:42

    let handler = {
        get:function (target,name) {
             return (
                 name in target ? target[name] : 42
        )
        }
    }
    
  • 現(xiàn)在,我們通過傳遞target和handler對象來創(chuàng)建一個新的代理。我們的代碼可以與代理交互,而不是直接訪問目標對象

    const proxy = new Proxy(target,handler);
    console.log(proxy.a);  //1 proxy代理了target對象
    console.log(proxy.b);  //2
    console.log(proxy.c);  //3
    console.log(proxy.random);  //42
    
    
  • 現(xiàn)在我們進一步擴大代理處理機制,這樣它只允許從a-z的單字符進行屬性設(shè)置

  • const target = {
        a:1,
        b:2,
        c:3
    };
    const handler = {
        
        get:function (target,name) {
            return (name in target ?target[name] :42);
        },
        set:function (target, prop,value) {
            if(prop.length == 1 && prop >='a' && prop <= 'z') {
                target[prop] = value;
                return true;
            } else {
                throw new ReferenceError(prop + '不能被設(shè)置');  //這里就拋出錯誤,不會再往下進行
                return false;
            }
        }
    };
    const proxy = new Proxy(target,handler);
    proxy.a = 10;
    proxy.b = 20;
    proxy.ABC = 30;  //這個會報錯,
    
    

Proxy的traps方法類型:

construct(target, argList) 當使用new構(gòu)建新對象時
get(target, property) 該方法必須返回屬性value值
set(target, property, value) 該方法用于攔截設(shè)置屬性值的操作,成功時返回時true;嚴格模式下返回false的時候會拋出一個TypeError異常
deleteProperty(target,property) 刪除對象中的屬性 ,返回的必須是true或false
apply(target,thisArg,argList) has(target,property)
has(target,property) 可以看作時針對in操作的鉤子, 返回值必須是true或false
ownKeys(target) 訪問Object.getOwnPropertyNames(), 必須返回一個可枚舉的對象
getPrototypeOf(target) 當?shù)厝ゴ韺ο蟮脑蜁r調(diào)用,必須返回原型的對象或者null
setPrototypeOf(target,prototype) 設(shè)置原型對象,沒有返回值
isExtensible(target) 訪問Object.isExtensible(),它決定了一個對象是否能有新添加的屬性,不稀罕會true或false
perventExtensions(target) 防止新屬性添加到對象中,必須返回true或false
getOwnPropertyDescriptor(target,property) 它返回undefined或?qū)傩缘拿枋觯簐alue,writable,get,set,configurable,enumerable
defineProperty(target,property,descriptor) 定義或修改對象屬性,必須返回true或false。當target屬性成功定義返回true,否則返回false
  • Proxies代理允許你為人和對象創(chuàng)建通用的包裝器,而不需要改變目標對象本身的代碼

eg1: 創(chuàng)建剖析代理

  • 用以計算屬性被訪問的次數(shù)。makeProfiler工廠函數(shù),會返回Proxy對象,保留計算的狀態(tài):

  • function makeProfiler(target) {
        const count = {},
              handler = {
            get:function (target,name) {  //傳的是你的對象
                if(name in target) {
                     count[name] = (count[name] || 0) + 1; //關(guān)鍵點
                    return target[name];  //get方法必須返回屬性value值
                }
            }
              };
        return {
            proxy:new Proxy(target,handler),
            count:count
        }
    }
    
  • 現(xiàn)在我們可以用上面封裝好的proxy外殼應(yīng)用于所有的對象或者其他代理,:

    const myObject = {
        h:'hello',
        w:'world'
    };
    
  • 創(chuàng)建myObject代理

    const pObj = makeProfiler(myObject);
    
    console.log(pObj.proxy.h); //hello
    console.log(pObj.proxy.h);  //hello  訪問了兩次,count = 2;
    console.log(pObj.proxy.w);  //world
    console.log(pObj.count.h);  //2
    console.log(pObj.count.w);  //1
    

eg2:雙向綁定

  • 數(shù)據(jù)綁定同步對象。當DOM發(fā)生變化時,JavaScript的MVC庫通常使用它來更新內(nèi)部對象,反之亦然。

    1. 創(chuàng)建一個input標簽,id是inputName
  • <input type="text" id="'inputName" />
    
  • 創(chuàng)建myUser對象,

  • const myUser = {
         id:'inputname',
         name:''
     }
    
  • 當用戶改變input輸入值時,更新myUser里的name,通過onchange事件處理程序來實現(xiàn)

  • inputChange(myUser);
    
    function inputChange(myObject) {
        if (!myObject || !myObject.id) return;  //如果傳入的對象不存在或者沒有id屬性,return出去
        const input = document.getElementById(myObject.id);
        input.addEventListener('onchange', function(e) {
            myObject.name = input.value;
        });
    }
    
  • 在js代碼中修改myUse.name時,跟新input里的內(nèi)容,這一步略微復雜,但是proxy代理提供了一個解決方案

  •   const inputHandler = {
         set:function (target,prop,newValue) {
             if(prop =='name' && target.id ) { //prop指的是傳入的對象里的屬性:
                 //更新對象的屬性
                target[prop] = newValue;
                document.getElementById(target.id).value = newValue;
                return true;  //set方法返回值只有false或true;
             }
             else return false;
         }
        };
    
    
  • 創(chuàng)建Proxy

  •  const myUserProxy = new Proxy(myUser,inputHandler);
    
  • 手動設(shè)置新name

  •     myUserProxy.name = 'Lily';
        console.log(myUserProxy.name);  //Lily
        console.log(document.getElementById('inputName').value);  //Lily
    
  • 這不一定是最有效的數(shù)據(jù)綁定選項,但是
    Proxy代理可以允許你在不更改其他代碼的情況下改變好多現(xiàn)有對象的行為

  • 點擊鏈接查看: 如何通過Proxy 結(jié)合原生js/或jQuery實現(xiàn)類似vue的數(shù)據(jù)雙向綁定

目前Proxy的力量不一定是那么顯而易見,但是它們提供了強大的元編程機會,JavaScript的創(chuàng)造者--Brendan Eich就認為,Proxy很贊!
  • 目前,Proxy在node和各大瀏覽器都可以實現(xiàn),除了IE11以外,但也要注意,不是所有的瀏覽器支持traps,查Proxy瀏覽器支持度:


    Proxy內(nèi)建方法的各大瀏覽器支持度
  • 壞消息: 目前不能通過轉(zhuǎn)換工具如Babel將es6的Proxy編譯成es5代碼,誰讓proxies這么強大呢!~

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容