<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>

                企業??AI智能體構建引擎,智能編排和調試,一鍵部署,支持知識庫和私有化部署方案 廣告
                元編程:操作程序本身行為特性的編程 元編程關注以下幾點:代碼查看自身、代碼修改自身、代碼修改默認特性、影響其他代碼 #### 元屬性new.target new.target總是訪問真正new的目標的上下文 ``` class Parent { constructor() { if(new.target === parent) console.log('Parent instantiated'); else console.log('Child instantiated'); } } class Child extends Parent {} var a = new Parent(); //Parent instantiated var b = new Child(); //Child instantiated ``` #### 公開符號 symbol對外提供了一些公共的符號 `Symbol.iterator` 例如...、for...of都是自動使用Symbol.iterator的,它是對象上的一個專門屬性,它會自動查找對象上有沒有一個方法(可以構造一個迭代器來消耗這個對象的值)。你也可以重寫: ``` var arr = [1, 2, 3]; arr[Symbol.iterator] = function *() { ... } ``` `Symbol.toStringTag`和`Symbol.hasInstance` ``` function Foo() {} var a = new Foo(); a.toString(); //[object Object] a instanceOf Foo; //true //Symbol.toStringTag和Symbol.hasInstance更改上述結果 function Foo() {} Foo.prototype[Symbol.toStringTag] = "Foo"; Object.defineProperty(Foo, Symbol.hasInstance, { value: obj => false }); //必須使用Object.defineProperty來使用Symbol.hasInstance,因為Function.prototype上的那個的writable是false //obj就是FOO的實例,比如是a、b var a = new Foo(); var b = new Foo(); b[Symbol.toStringTag] = "cool"; a.toString; //[object Foo]; b.toString; //[object cool]; a instanceof Foo; //false b instanceof Foo; //false ``` `Symbol.toPrimitive` ``` var arr = [1, 2, 3, 4, 5]; arr + 10; //1,2,3,4,510 arr[Symbol.toPrimitive] = function(hint) { //默認期望的運算類型,在這里是default,也是number //對于arr + 10來說,hint是default(number) //對于arr * 10來說,hint是number //對于String(arr)來說,hint是string if(hint == "default" || hint == "number") { return this.reduce(function(acc, curr) { return acc + curr }, 0); } }; arr + 10; //25 ``` `Symbol.isConcatSpreadable` ``` var a = [1, 2, 3], b = [4, 5, 6]; [].concat(a, b); //[1, 2, 3, 4, 5, 6]; b[Symbol.isConcatSpreadable] = false; [].concat(a, b); //[1, 2, 3, [4, 5, 6]] ``` #### 代理 代理是一種特殊的對象,它封裝了一個普通的對象,作為該普通對象的攔截器。 ``` var obj = {a: 1}; var pobj = new Proxy(obj, { get: function(target, key, receiver) { console.log(target, key); return Reflect.get(target, key, receiver); } }); //攔截obj的get方法做出一系列操作后通過Reflect.get轉發該操作(在這里是到默認操作上) obj.a; //1 pobj.a; //{a: 1} a //1 ``` 每一個代理trap都有一個與之同名的Reflect api,在這里是get ``` //列舉Proxy可用trap 1.get:在代理上訪問一個屬性:Reflect.get(obj)、obj[]、obj. 2.set:在代理上設置一個屬性:為對象賦值或解構等操作 3.deleteProperty:從代理對象上刪除一個屬性 4.Reflect.deleteProperty(obj)或delete obj 5.apply(如果目標是函數的話):將代理作為普通函數調用 6.Reflect.apply、Reflect.call、func.apply、func.call 7.defineProperty 8.getPrototypeOf 9.setPrototypeOf 10.has ``` 可取消的代理 ``` var obj = {a: 1}; var handlers = { get(target, key, receiver) { console.log("accessing: ", key); return target[key]; } }; //普通的代理是new Proxy()創建,而可取消代理只能這樣創建 var {proxy: pobj, revoke: prevoke} = Proxy.revocable(obj, handlers); pobj.a; //accessing: a //1 prevoke(); pobj.a; //TypeError //一旦代理被取消,所有對代理的操作均會TypeError ``` 使用代理 日常中,建議實際操作的是代理,而元對象被隱藏起來 ``` //代理在先(首先與、主要或完全代理交互) var message = []; handlers = { get(target, key) { if(typeof target[key] === 'string') { //過濾掉標點符號 return target[key].replace(/[^\w]/g, ""); } return target[key]; }, set(target, key, val) { if(typeof val === "string") { val = val.toLowerCase(); if(target.indexOf(val) === -1) target.push(val.toLowerCase()) } return true; } } var message_proxy = new Proxy(messages, handlers); message_proxy.push("hello...", 42, "wOrlD!!", "WoRlD!!"); //遍歷message_proxy //hello world //遍歷messages //hello... world!! ``` ``` //代理在后(代碼只能與主對象交互,實在不行了再與代理交互) var handlers = { get(target, key, receiver) { return function() { receiver.speak(key + "!") } } }; var catchall = new Proxy({}, handlers);//換成greeter結果也一樣 var greeter = {speak(who) {console.log("hello", who)}}; Object.setPrototypeOf(greeter, catchall); greeter.speak(); //hello undefined greeter.speak("world"); //hello world greeter.everyone(); //hello everyone! //代理作為greeter的原型,用戶直接與greeter交流,而greeter沒有everyone方法,js會順著原型鏈找到代理查看代理有沒有這個屬性,此時會觸發代理的get ``` No such property or method ``` //有時候,我們期望只有屬性存在的時候才對該屬性進行操作 var obj = {a: 1, foo(){ console.log(this.a) }}; handlers = { get(target, key, receiver) { if(Reflect.has(target, key)) { return Reflect.get(target, key, receiver); } else { throw 'No such property/method'; } }, set(target, key, receiver) { if(Reflect.has(target, key)) { return Reflect.set(target, key, receiver); } else { throw 'No such property/method'; } } } var pobj = new Proxy(obj, handlers); pobj.a = 3; pobj.foo(); //3 pobj.b = 4; //Error: no such property/method pobj.bar(); //Error: no such property/method //代理在后 var handlers = { get() { throw 'No such property/method'; } set() { throw 'No such property/method'; } } pobj = new Proxy({}, handlers); Object.setProtytypeOf(obj, pobj); pobj.a = 3; pobj.foo(); //3 pobj.b = 4; //Error: no such property/method pobj.bar(); //Error: no such property/method ``` 代理[[proptotype]]鏈 ``` //[[prototype]]機制的原理就是[[Get]]運算,當對象自身沒有某個屬性時,[[Get]]會自動把這個運算轉給[[prototype]]處理 //我們可以用代理做一個原型環 var handlers = { get(target, key, receiver) { if(Reflect.has(target, key)) { return Reflect.get(target, key, receiver); } //直接對象沒有該屬性,則訪問我們自定義的原型 else { return Reflect.get( target[Symbol("[[Prototype]]")], key, receiver ); } } } var obj1 = new Proxy({ name: 'obj-1', foo() { console.log('foo': this.name) } }, handlers); var obj2 = Object.assign(Object.create(obj1), { name: 'obj-2', bar() { console.log('bar: ', this.name); this.foo(); } }); obj1[Symbol.for("[[Prototype]]")] = obj2; //現在,obj2.prototype是obj1,而obj1的Symbol("[[Prototype]]")是obj2 //當obj1某個屬性沒有時,會代理到Symbol("[[Prototype]]")上,也就是obj2上 obj1.bar(); //bar: obj1 //foo: obj1 //因為obj1有name,所以訪問的是obj1的name obj2.foo(); //foo: obj2 //因為obj12沒有foo,通過Prototype訪問obj1的foo ``` ``` //不用原型環,應用:為一個對象創建多個“Prototype” var obj1 = { name: 'obj-1', foo() { console.log('obj1.foo: ', this.name) } } var obj2 = { name: 'obj-2', foo() { console.log('obj2.foo', this.name) }, bar() { console.log('obj2.bar', this.name) } } var handlers = { get(target, key, receiver) { if(Reflect.has(target, key)) { return Reflect.get(target, key, receiver); } else { for(var p of target[Symbol.for("[[Prototype]]")]) { if(Reflect.has(p, key)) { return Reflect.get(p, key, receiver) } } } } } var obj3 = new Proxy({ name: 'obj-3', baz() { this.foo(); this.bar(); } }, handlers) obj3[Symbol.for("[[Prototype]]")] = [obj1, obj2] obj3.baz(); //obj1.foo: obj-3 //obj2.bar: obj-3 ``` #### Reflect API 設計初衷: * 將Object對象的一些明顯屬于語言內部的方法(比如Object.defineProperty),放到Reflect對象上,未來所有操作內部api的事情全部交由Reflect來做,而不是Object.。 * 修改了某些Object方法的返回結果,讓其變得更合理。 Reflect的api與Proxy的trap一一對應,參考Proxy的那些trap。 Reflect API的第一個參數永遠是目標對象,如果它不是一個對象,則會報錯。 屬性排序 ``` //一般的,對象的屬性列出順序是依賴于定義順序的 //而我們可以使用Reflect.ownKeys將列出順序改為es6的[[OwnPropertyKeys]]算法列出的順序 //Object.getOwnPropertyNames和Object.getOwnPropertySymbols也是按照該算法,只不過它們只能列出各自的 var o = { [Symbol("c")]: "yay", 2: true, 1: true, b: "awesome", a: "cool" } Reflect.ownKeys(o); //[1, 2, "b", "a", Symbol(c)] Object.getOwnPropertyNames(o); //[1, 2, "b", "a"] Object.getOwnPropertySymbols(o); //[Symbol(c)] //JSON.stringify(obj)不會考慮obj的原型鏈,它只會stringify obj自身的屬性并返回 ``` #### 尾調用 尾調用的概念非常簡單,一句話就能說清楚,就是指某個函數的最后一步是調用另一個函數。 ``` function f(x){ return g(x); } //函數f的最后一步是調用函數g,這就叫尾調用。 //下面的都不是尾調用 // 情況一 //調用g后,將其賦值給y然后再返回y function f(x){ let y = g(x); return y; } // 情況二 //調用g后,將結果+1再返回 function f(x){ return g(x) + 1; } ``` 尾調用不一定出現在函數尾部,只要是最后一步操作即可。 ``` function f(x) { if (x > 0) { return m(x) } return n(x); } //上面代碼中,函數m和n都屬于尾調用,因為它們都是函數f的最后一步操作。 ``` 尾調用之所以與其他調用不同,就在于它的特殊的調用位置。 我們知道,函數調用會在內存形成一個"調用記錄",又稱"調用幀"(call frame),保存調用位置和內部變量等信息。如果在函數A的內部調用函數B,那么在A的調用記錄上方,還會形成一個B的調用記錄。等到B運行結束,將結果返回到A,B的調用記錄才會消失。如果函數B內部還調用函數C,那就還有一個C的調用記錄棧,以此類推。所有的調用記錄,就形成一個["調用棧"](http://zh.wikipedia.org/wiki/%E8%B0%83%E7%94%A8%E6%A0%88)(call stack)。![](http://upload-images.jianshu.io/upload_images/1495096-a00b4b60e0585207..png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 尾調用由于是函數的最后一步操作,所以不需要保留外層函數的調用記錄,因為調用位置、內部變量等信息都不會再用到了,只要直接用內層函數的調用記錄,取代外層函數的調用記錄就可以了。 尾調用具體請參考[阮一峰的尾調用](http://www.ruanyifeng.com/blog/2015/04/tail-call.html) EventLoop具體請參考[阮一峰的EventLoop](http://www.ruanyifeng.com/blog/2014/10/event-loop.html)
                  <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>

                              哎呀哎呀视频在线观看