<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                合規國際互聯網加速 OSASE為企業客戶提供高速穩定SD-WAN國際加速解決方案。 廣告
                &emsp;&emsp;代理和反射是ES6新增的兩個特性,兩者之間是協調合作的關系,它們的具體功能將在接下來的章節中分別講解。 ## 一、代理 &emsp;&emsp;ES6引入代理(Proxy)地目的是攔截對象的內置操作,注入自定義的邏輯,改變對象的默認行為。也就是說,將某些JavaScript內部的操作暴露了出來,給予開發人員更多的權限。這其實是一種元編程(metaprogramming)的能力,即把代碼看成數據,對代碼進行編程,改變代碼的行為。 &emsp;&emsp;在ES6中,代理是一種特殊的對象,如果要使用,需要像下面這樣先生成一個Proxy實例。 ~~~ new Proxy(target, handler); ~~~ &emsp;&emsp;構造函數Proxy()有兩個參數,其中target是要用代理封裝的目標對象,handler也是一個對象,它的方法被稱為陷阱(trap),用于指定攔截后的行為。下面是一個代理的簡單示例。 ~~~ var obj = {}, handler = { set(target, property, value, receiver) { target[property] = "hello " + value; } }, p = new Proxy(obj, handler); p.name = "strick"; console.log(p.name); //"hello strick" ~~~ &emsp;&emsp;在上面的代碼中,p是一個Proxy實例,它的目標對象是obj,使用了屬性相關的陷阱:set()方法。當它寫入obj的name屬性時,會對其進行攔截,在屬性值之前加上“hello ”前綴。除了上例使用的set()方法,ES6還給出了另外12種可用的陷阱,在后面的章節中會對它們做簡單的介紹。 **1)陷阱** &emsp;&emsp;表12羅列了目前所有可用的陷阱,第二列表示當前陷阱可攔截的行為,注意,只挑選了其中的幾個用于展示。 :-: ![](https://img.kancloud.cn/e3/57/e357af899d9664edec85ebb796cc5f92_1311x1317.png) :-: 表12 十三種陷阱 &emsp;&emsp;目前支持的攔截就上面幾種,像typeof運算符、全等比較等操作還不被ES6支持。接下來會挑選其中的兩次個陷阱,講解它們的簡單應用。 &emsp;&emsp;在JavaScript中,當讀取對象上不存在的屬性時,不會報錯而是返回undefined,這其實在某些情況下會發生歧義,現在利用陷阱中的get()方法就能改變默認行為,如下所示。 ~~~ var obj = { name: "strick" }, handler = { get(target, property, receiver) { if(property in target) return target[property]; throw "未定義的錯誤"; } }, p = new Proxy(obj, handler); p.name;   //"strick" p.age; //未定義的錯誤 ~~~ &emsp;&emsp;在get()方法中有3個參數,target是目標對象(即obj),property是讀取的屬性的名稱(即“name”和“age”),receiver是當前的Proxy實例(即p)。在讀取屬性時,會用in運算符判斷當前屬性是否存在,如果存在就返回相應的屬性值,否則就會拋出錯誤,這樣就能避免歧義的出現。 &emsp;&emsp;在眾多陷阱中,只有apply()和construct()的目標對象得是函數。以apply()方法為例,它有3個參數,target是目標函數,thisArg是this的指向,argumentsList是函數的參數序列,它的具體使用如下所示。 ~~~ function getName(name) { return name; } var obj = { prefix: "hello " }, handler = { apply(target, thisArg, argumentsList) { if(thisArg && thisArg.prefix) return target(thisArg.prefix + argumentsList[0]); return target(...argumentsList); } }, p = new Proxy(getName, handler); p("strick");     //"strick" p.call(obj, "strick"); //"hello strick" ~~~ &emsp;&emsp;p是一個Proxy實例,p("strick")是一次普通的函數調用,此時雖然攔截了,但是仍然會把參數原樣傳過去;而p.call(obj, "strick")是間接的函數調用,此時會給第一個參數添加前綴,從而改變函數最終的返回值。 **2)撤銷代理** &emsp;&emsp;Proxy.revocable()方法能夠創建一個可撤銷的代理,它能接收兩個參數,其含義與構造函數Proxy()中的相同,但返回值是一個對象,包含兩個屬性,如下所列。 &emsp;&emsp;(1)proxy:新生成的Proxy實例。 &emsp;&emsp;(2)revoke:撤銷函數,它沒有參數,能把與它一起生成的Proxy實例撤銷掉。 &emsp;&emsp;下面是一個簡單的示例,obj是目標對象,handler是陷阱對象,傳遞給Proxy.revocable()后,通過對象解構將返回值賦給了proxy和revoke兩個變量。 ~~~ var obj = {}, handler = {}; let {proxy, revoke} = Proxy.revocable(obj, handler); revoke(); delete proxy.name; //類型錯誤 typeof proxy; //"object" ~~~ &emsp;&emsp;在調用revoke()函數后,就不能再對proxy進行攔截了。像上例使用delete運算符,就會拋出類型錯誤,但像typeof之類的不可攔截的運算符還是可以成功執行的。 **3)原型** &emsp;&emsp;代理可以成為其它對象的原型,就像下面這樣。 ~~~ var obj = { name: "strick" }, handler = { get(target, property, receiver) { if(property == "name") return "hello " + target[property]; return true; } }, p = new Proxy({}, handler); Object.setPrototypeOf(obj, p); //obj的原型指向Proxy實例 obj.name;        //"strick" obj.age;        //true ~~~ &emsp;&emsp;p是一個Proxy實例,它會攔截屬性的讀取操作,obj的原型指向了p,注意,p的目標對象不是obj。當obj讀取name屬性時,不會觸發攔截,因為name是自有屬性,所以不會去原型上查找,最終得到的結果是沒有前綴的“strick”。之前的代理都是直接作用于相關對象(例如上面的obj),因此只要執行可攔截的動作就會被處理,但現在中間隔了個原型,有了更多的限制。而在讀取age屬性時,由于自有屬性中沒有它,因此就會去原型上查找,從而觸發了攔截操作,返回了true。 ## 二、反射 &emsp;&emsp;反射(Reflect)向外界暴露了一些底層操作的默認行為,它是一個沒有構造函數的內置對象,類似于Math對象,其所有方法都是靜態的。代理中的每個陷阱都會對應一個同名的反射方法(例如Reflect.set()、Reflect.ownKeys()等),而每個反射方法又都會關聯到對應代理所攔截的行為(例如in運算符、Object.defineProperty()等),這樣就能保證某個操作的默認行為可隨時被訪問到。反射讓對象的內置行為變得更加嚴謹、合理與便捷,具體表現如下所列。 &emsp;&emsp;(1)參數的檢驗更為嚴格,Object的getPrototypeOf()、isExtensible()等方法會將非對象的參數自動轉換成相應的對象(例如字符串轉換成String對象,如下代碼所示),而關聯的反射方法卻不會這么做,它會直接拋出類型錯誤。 ~~~ Object.getPrototypeOf("strick") === String.prototype;     //true Reflect.getPrototypeOf("strick");       //類型錯誤 ~~~ &emsp;&emsp;(2)更合理的返回值,Object.setPrototypeOf()會返回它的第一個參數,而Reflect的同名方法會返回一個布爾值,后者能更直觀的反饋設置是否成功,兩個方法的對比如下所示。 ~~~ var obj = {}; Object.setPrototypeOf(obj, String) === obj;    //true Reflect.setPrototypeOf(obj, String);   //true ~~~ &emsp;&emsp;(3)用方法替代運算符,反射能以調用方法的形式完成new、in、delete等運算符的功能,在下面的示例中,先使用運算符,再給出對應的反射方法。 ~~~ function func() { } new func(); Reflect.construct(func, []); var people = { name: "strick" }; "name" in people; Reflect.has(people, "name"); delete people["name"]; Reflect.deleteProperty(people, "name"); ~~~ &emsp;&emsp;(4)避免冗長的方法調用,以apply()方法為例,如下所示。 ~~~ Function.prototype.apply.call(Math.ceil, null, [2.5]);   //3 Reflect.apply(Math.ceil, null, [2.5]);      //3 ~~~ &emsp;&emsp;上面代碼的第一條語句比較繞,需要將其分解成兩部分:Function.prototype.apply()和call()。ES5規定apply()和call()兩個方法在最后都要調用一個有特殊功能的內部函數,如下代碼所示,func參數表示調用這兩個方法的函數。 ~~~ [[Call]](func, thisArg, argList) ~~~ &emsp;&emsp;內部函數的功能就是在調用func()函數時,傳遞給它的參數序列是argList,其內部的this指向了thisArg。當執行第一條語句時,傳遞給\[\[Call\]\]函數的三個參數如下所示。 ~~~ [[Call]](Function.prototype.apply, Math.ceil, [null, [2.5]]) ~~~ &emsp;&emsp;接下來會調用原型上的apply()方法,由于其this指向了Math.ceil(即當前調用apply()方法的是Math.ceil),因此\[\[Call\]\]函數的第一個參數就是Math.ceil,如下所示。 ~~~ [[Call]](Math.ceil, null, [2.5]) //相當于 Math.ceil.apply(null, [2.5]) ~~~ ***** > 原文出處: [博客園-ES6躬行記](https://www.cnblogs.com/strick/category/1372951.html) [知乎專欄-ES6躬行記](https://zhuanlan.zhihu.com/pwes6) 已建立一個微信前端交流群,如要進群,請先加微信號freedom20180706或掃描下面的二維碼,請求中需注明“看云加群”,在通過請求后就會把你拉進來。還搜集整理了一套[面試資料](https://github.com/pwstrick/daily),歡迎瀏覽。 ![](https://box.kancloud.cn/2e1f8ecf9512ecdd2fcaae8250e7d48a_430x430.jpg =200x200) 推薦一款前端監控腳本:[shin-monitor](https://github.com/pwstrick/shin-monitor),不僅能監控前端的錯誤、通信、打印等行為,還能計算各類性能參數,包括 FMP、LCP、FP 等。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看