<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智能體構建引擎,智能編排和調試,一鍵部署,支持知識庫和私有化部署方案 廣告
                [TOC] # 子類化內置構造函數 JavaScript內置的構造函數很難子類化。這一章解釋了原因并提出了解決方案。 ## 術語 我們使用了一個*內置的子類*,避免了術語擴展,因為它是用JavaScript編寫的: * 子類化一個內置的`A` 創建一個給定的內置構造函數`A`的子構造函數`B`。`B`的實例也是`a`的實例。 * 擴展`obj`對象 復制一個對象屬性到另一個對象中。 `Underscore.js`[使用了這個術語](http://underscorejs.org/#extend),延續了`Prototype`框架建立的傳統。 子類化內置對象有兩個障礙:具有內部屬性的實例和不能作為函數調用的構造函數。 ## 障礙1:具有內部屬性的實例 大多數內置構造函數都有*具有所謂的內部屬性*(見[屬性種類](###第17章))的實例,其名稱用雙方括號表示,如下所示:`[[PrimitiveValue]]`。內部屬性由JavaScript引擎管理,通常不能直接通過JavaScript訪問。JavaScript中的正常子類化技術是傳入子構造函數中的`this`來調用父級構造函數。(請參閱[第4節:構造函數之間的繼承](###第17章)): ```js function Super(x, y) { this.x = x; // (1) this.y = y; // (1) } function Sub(x, y, z) { // Add superproperties to subinstance Super.call(this, x, y); // (2) // Add subproperty this.z = z; } ``` 大多數內置函數忽略了`(2)`中作為`this`傳入的子實例,這是下一節中描述的一個障礙。此外,將內部屬性添加到現有實例`(1)`通常是不可能的,因為它們傾向于從根本上改變實例的性質。因此,`(2)`的調用不能用于添加內部屬性。以下構造函數都有*內部屬性*的實例: **包裝器構造函數** `Boolean`、`Number`和`String`的實例其實包裝了原始值.它們都具有通過`valueOf()`返回的 `[[PrimitiveValue]]`這個內部屬性。 `String`有兩個附加的實例屬性: * Boolean:內部實例屬性`[[PrimitiveValue]]`。 * Number:內部實例屬性`[[PrimitiveValue]]`。 * String:內部實例屬性`[[PrimitiveValue]]`,自定義內部實例方法`[[GetOwnProperty]]`,普通實例屬性`length`。當使用數組索引時,`[[GetOwnProperty]]`可以實現通過從包裝好的字符串中讀取數據,對字符進行索引訪問。 1. Array: 自定義內部實例方法`[[DefineOwnProperty]]`可以阻止屬性被設置。它確保屬性`length`正常工作,可以在添加數組元素時保持`length`處于最新值,并在`length`變小時刪除多余的元素。 2. Date: 內部實例屬性`[[PrimitiveValue]]`存儲了由日期實例表示的時間(自1970年1月1日00:00:00 UTC的**毫秒數**)。 3. Function: 內部實例屬性`[[Call]]`(當一個實例被調用時執行的該代碼)和其他可能的代碼 4. RegExp: 內部實例屬性 `[[Match]]`,加上兩個非內部的實例屬性。下面是來自ECMAScript的規范: > 內部實例屬性`[[Match]]`的值是RegExp對象的模式的實現依賴表示。 **唯一沒有內部屬性的內置構造函數是`Error`和`Object`。** ### 障礙1的解決方法 `MyArray`是`Array`的子類。它有一個名為`size`的 getter ,返回了數組中的實際元素,忽略了漏洞(在這里`length`考慮了漏洞)。實現`MyArray`的技巧是它創建一個數組實例并將其方法復制到其中(受到Ben Nadel的一篇[博客文章](https://www.bennadel.com/blog/2292-extending-javascript-arrays-while-keeping-native-bracket-notation-functionality.htm)的啟發): ```js function MyArray(/*arguments*/) { var arr = []; // Don’t use Array constructor to set up elements (doesn’t always work) Array.prototype.push.apply(arr, arguments); // (1) copyOwnPropertiesFrom(arr, MyArray.methods); return arr; } MyArray.methods = { get size() { var size = 0; for (var i=0; i < this.length; i++) { if (i in this) size++; } return size; } } ``` 這個代碼使用了輔助函數`copyownproperties()`,這個函數在[復制對象](###第17章#code_copyOwnPropertiesFrom)章節中說過了。 我們不會在行`(1)`中調用`Array`的構造函數,因為一個怪癖:如果用一個參數來調用它,那么這個數字就不會成為一個元素,只是一個空數組的長度(參見用[元素(注意事項!)初始化一個數組](###第18章#avoid_array_constructor))。 這是交互運行結果: ```js > var a = new MyArray('a', 'b') > a.length = 4; > a.length 4 > a.size 2 ``` ### 注意 將方法復制到實例會導致冗余,這可以通過原型來避免(如果我們有這個選擇)。此外,`MyArray`創建的對象不是它的實例: ```js > a instanceof MyArray false > a instanceof Array true ``` ## 障礙2:內置的構造函數不能作為方法調用 即使`Error`和子類沒有具有內部屬性的實例,您仍然無法輕松地對其進行子類化,因為子類化的標準模式行不通(上述代碼重復): ```js function Super(x, y) { this.x = x; this.y = y; } function Sub(x, y, z) { // Add superproperties to subinstance Super.call(this, x, y); // (1) // Add subproperty this.z = z; } ``` 問題是`Error`總是產生一個新的實例,在`(1)`,即使作為一個函數被調用;也就是說,在`call()`方式中它忽略了傳遞給它的參數`this`: ```js > var e = {}; > Object.getOwnPropertyNames(Error.call(e)) // new instance [ 'stack', 'arguments', 'type' ] > Object.getOwnPropertyNames(e) // unchanged [] ``` 在前面的交互中,`Error`返回一個具有自己屬性的實例,但它是一個新的實例,而不是`e`。子類化模式只有在`Error`將自己的屬性添加到`this`(`e`,在前面的例子中)時才會起作用。 ### 障礙2的解決方法 在子構造函數中,創建一個新的父級實例并將其自己的屬性復制到子實例: ```js function MyError() { // Use Error as a function var superInstance = Error.apply(null, arguments); copyOwnPropertiesFrom(this, superInstance); } MyError.prototype = Object.create(Error.prototype); MyError.prototype.constructor = MyError; ``` 再次使用提到過的的`copyownproperties()`。嘗試`MyError`: ```js try { throw new MyError('Something happened'); } catch (e) { console.log('Properties: '+Object.getOwnPropertyNames(e)); } ``` 下面是在`node.js`下的輸出: ~~~ Properties: stack,arguments,message,type ~~~ 該實例之間的關系是: ```js > new MyError() instanceof Error true > new MyError() instanceof MyError true ``` ## 另一種解決方案:委托 委托可以非常干凈的替代子類。例如,要創建自己的數組構造函數,您需要在屬性中保留一個數組:。 ```js function MyArray(/*arguments*/) { this.array = []; Array.prototype.push.apply(this.array, arguments); } Object.defineProperties(MyArray.prototype, { size: { get: function () { var size = 0; for (var i=0; i < this.array.length; i++) { if (i in this.array) size++; } return size; } }, length: { get: function () { return this.array.length; }, set: function (value) { return this.array.length = value; } } }); ``` 最明顯的限制是,你不能通過方括號的形式訪問`MyArray`的元素;您必須使用這樣的方法: ```js MyArray.prototype.get = function (index) { return this.array[index]; } MyArray.prototype.set = function (index, value) { return this.array[index] = value; } ``` 可以通過以下元編程來傳輸`Array.prototype`上的普通方法: ```js [ 'toString', 'push', 'pop' ].forEach(function (key) { MyArray.prototype[key] = function () { return Array.prototype[key].apply(this.array, arguments); } }); ``` 通過存儲在`MyArray`實例中的數組`this.array`上調用它們,我們從`Array`的方法中獲得了`MyArray`方法。 使用`MyArray`: ```js > var a = new MyArray('a', 'b'); > a.length = 4; > a.push('c') 5 > a.length 5 > a.size 3 > a.set(0, 'x'); > a.toString() 'x,b,,,c' ```
                  <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>

                              哎呀哎呀视频在线观看