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

                ??碼云GVP開源項目 12k star Uniapp+ElementUI 功能強大 支持多語言、二開方便! 廣告
                # Object 對象的相關方法 JavaScript 在`Object`對象上面,提供了很多相關方法,處理面向對象編程的相關操作。本章介紹這些方法。 ## Object.getPrototypeOf() `Object.getPrototypeOf`方法返回參數對象的原型。這是獲取原型對象的標準方法。 ```javascript var F = function () {}; var f = new F(); Object.getPrototypeOf(f) === F.prototype // true ``` 上面代碼中,實例對象`f`的原型是`F.prototype`。 下面是幾種特殊對象的原型。 ```javascript // 空對象的原型是 Object.prototype Object.getPrototypeOf({}) === Object.prototype // true // Object.prototype 的原型是 null Object.getPrototypeOf(Object.prototype) === null // true // 函數的原型是 Function.prototype function f() {} Object.getPrototypeOf(f) === Function.prototype // true ``` ## Object.setPrototypeOf() `Object.setPrototypeOf`方法為參數對象設置原型,返回該參數對象。它接受兩個參數,第一個是現有對象,第二個是原型對象。 ```javascript var a = {}; var b = {x: 1}; Object.setPrototypeOf(a, b); Object.getPrototypeOf(a) === b // true a.x // 1 ``` 上面代碼中,`Object.setPrototypeOf`方法將對象`a`的原型,設置為對象`b`,因此`a`可以共享`b`的屬性。 `new`命令可以使用`Object.setPrototypeOf`方法模擬。 ```javascript var F = function () { this.foo = 'bar'; }; var f = new F(); // 等同于 var f = Object.setPrototypeOf({}, F.prototype); F.call(f); ``` 上面代碼中,`new`命令新建實例對象,其實可以分成兩步。第一步,將一個空對象的原型設為構造函數的`prototype`屬性(上例是`F.prototype`);第二步,將構造函數內部的`this`綁定這個空對象,然后執行構造函數,使得定義在`this`上面的方法和屬性(上例是`this.foo`),都轉移到這個空對象上。 ## Object.create() 生成實例對象的常用方法是,使用`new`命令讓構造函數返回一個實例。但是很多時候,只能拿到一個實例對象,它可能根本不是由構建函數生成的,那么能不能從一個實例對象,生成另一個實例對象呢? JavaScript 提供了`Object.create()`方法,用來滿足這種需求。該方法接受一個對象作為參數,然后以它為原型,返回一個實例對象。該實例完全繼承原型對象的屬性。 ```javascript // 原型對象 var A = { print: function () { console.log('hello'); } }; // 實例對象 var B = Object.create(A); Object.getPrototypeOf(B) === A // true B.print() // hello B.print === A.print // true ``` 上面代碼中,`Object.create()`方法以`A`對象為原型,生成了`B`對象。`B`繼承了`A`的所有屬性和方法。 實際上,`Object.create()`方法可以用下面的代碼代替。 ```javascript if (typeof Object.create !== 'function') { Object.create = function (obj) { function F() {} F.prototype = obj; return new F(); }; } ``` 上面代碼表明,`Object.create()`方法的實質是新建一個空的構造函數`F`,然后讓`F.prototype`屬性指向參數對象`obj`,最后返回一個`F`的實例,從而實現讓該實例繼承`obj`的屬性。 下面三種方式生成的新對象是等價的。 ```javascript var obj1 = Object.create({}); var obj2 = Object.create(Object.prototype); var obj3 = new Object(); ``` 如果想要生成一個不繼承任何屬性(比如沒有`toString()`和`valueOf()`方法)的對象,可以將`Object.create()`的參數設為`null`。 ```javascript var obj = Object.create(null); obj.valueOf() // TypeError: Object [object Object] has no method 'valueOf' ``` 上面代碼中,對象`obj`的原型是`null`,它就不具備一些定義在`Object.prototype`對象上面的屬性,比如`valueOf()`方法。 使用`Object.create()`方法的時候,必須提供對象原型,即參數不能為空,或者不是對象,否則會報錯。 ```javascript Object.create() // TypeError: Object prototype may only be an Object or null Object.create(123) // TypeError: Object prototype may only be an Object or null ``` `Object.create()`方法生成的新對象,動態繼承了原型。在原型上添加或修改任何方法,會立刻反映在新對象之上。 ```javascript var obj1 = { p: 1 }; var obj2 = Object.create(obj1); obj1.p = 2; obj2.p // 2 ``` 上面代碼中,修改對象原型`obj1`會影響到實例對象`obj2`。 除了對象的原型,`Object.create()`方法還可以接受第二個參數。該參數是一個屬性描述對象,它所描述的對象屬性,會添加到實例對象,作為該對象自身的屬性。 ```javascript var obj = Object.create({}, { p1: { value: 123, enumerable: true, configurable: true, writable: true, }, p2: { value: 'abc', enumerable: true, configurable: true, writable: true, } }); // 等同于 var obj = Object.create({}); obj.p1 = 123; obj.p2 = 'abc'; ``` `Object.create()`方法生成的對象,繼承了它的原型對象的構造函數。 ```javascript function A() {} var a = new A(); var b = Object.create(a); b.constructor === A // true b instanceof A // true ``` 上面代碼中,`b`對象的原型是`a`對象,因此繼承了`a`對象的構造函數`A`。 ## Object.prototype.isPrototypeOf() 實例對象的`isPrototypeOf`方法,用來判斷該對象是否為參數對象的原型。 ```javascript var o1 = {}; var o2 = Object.create(o1); var o3 = Object.create(o2); o2.isPrototypeOf(o3) // true o1.isPrototypeOf(o3) // true ``` 上面代碼中,`o1`和`o2`都是`o3`的原型。這表明只要實例對象處在參數對象的原型鏈上,`isPrototypeOf`方法都返回`true`。 ```javascript Object.prototype.isPrototypeOf({}) // true Object.prototype.isPrototypeOf([]) // true Object.prototype.isPrototypeOf(/xyz/) // true Object.prototype.isPrototypeOf(Object.create(null)) // false ``` 上面代碼中,由于`Object.prototype`處于原型鏈的最頂端,所以對各種實例都返回`true`,只有直接繼承自`null`的對象除外。 ## Object.prototype.\_\_proto\_\_ 實例對象的`__proto__`屬性(前后各兩個下劃線),返回該對象的原型。該屬性可讀寫。 ```javascript var obj = {}; var p = {}; obj.__proto__ = p; Object.getPrototypeOf(obj) === p // true ``` 上面代碼通過`__proto__`屬性,將`p`對象設為`obj`對象的原型。 根據語言標準,`__proto__`屬性只有瀏覽器才需要部署,其他環境可以沒有這個屬性。它前后的兩根下劃線,表明它本質是一個內部屬性,不應該對使用者暴露。因此,應該盡量少用這個屬性,而是用`Object.getPrototypeOf()`和`Object.setPrototypeOf()`,進行原型對象的讀寫操作。 原型鏈可以用`__proto__`很直觀地表示。 ```javascript var A = { name: '張三' }; var B = { name: '李四' }; var proto = { print: function () { console.log(this.name); } }; A.__proto__ = proto; B.__proto__ = proto; A.print() // 張三 B.print() // 李四 A.print === B.print // true A.print === proto.print // true B.print === proto.print // true ``` 上面代碼中,`A`對象和`B`對象的原型都是`proto`對象,它們都共享`proto`對象的`print`方法。也就是說,`A`和`B`的`print`方法,都是在調用`proto`對象的`print`方法。 ## 獲取原型對象方法的比較 如前所述,`__proto__`屬性指向當前對象的原型對象,即構造函數的`prototype`屬性。 ```javascript var obj = new Object(); obj.__proto__ === Object.prototype // true obj.__proto__ === obj.constructor.prototype // true ``` 上面代碼首先新建了一個對象`obj`,它的`__proto__`屬性,指向構造函數(`Object`或`obj.constructor`)的`prototype`屬性。 因此,獲取實例對象`obj`的原型對象,有三種方法。 - `obj.__proto__` - `obj.constructor.prototype` - `Object.getPrototypeOf(obj)` 上面三種方法之中,前兩種都不是很可靠。`__proto__`屬性只有瀏覽器才需要部署,其他環境可以不部署。而`obj.constructor.prototype`在手動改變原型對象時,可能會失效。 ```javascript var P = function () {}; var p = new P(); var C = function () {}; C.prototype = p; var c = new C(); c.constructor.prototype === p // false ``` 上面代碼中,構造函數`C`的原型對象被改成了`p`,但是實例對象的`c.constructor.prototype`卻沒有指向`p`。所以,在改變原型對象時,一般要同時設置`constructor`屬性。 ```javascript C.prototype = p; C.prototype.constructor = C; var c = new C(); c.constructor.prototype === p // true ``` 因此,推薦使用第三種`Object.getPrototypeOf`方法,獲取原型對象。 ## Object.getOwnPropertyNames() `Object.getOwnPropertyNames`方法返回一個數組,成員是參數對象本身的所有屬性的鍵名,不包含繼承的屬性鍵名。 ```javascript Object.getOwnPropertyNames(Date) // ["parse", "arguments", "UTC", "caller", "name", "prototype", "now", "length"] ``` 上面代碼中,`Object.getOwnPropertyNames`方法返回`Date`所有自身的屬性名。 對象本身的屬性之中,有的是可以遍歷的(enumerable),有的是不可以遍歷的。`Object.getOwnPropertyNames`方法返回所有鍵名,不管是否可以遍歷。只獲取那些可以遍歷的屬性,使用`Object.keys`方法。 ```javascript Object.keys(Date) // [] ``` 上面代碼表明,`Date`對象所有自身的屬性,都是不可以遍歷的。 ## Object.prototype.hasOwnProperty() 對象實例的`hasOwnProperty`方法返回一個布爾值,用于判斷某個屬性定義在對象自身,還是定義在原型鏈上。 ```javascript Date.hasOwnProperty('length') // true Date.hasOwnProperty('toString') // false ``` 上面代碼表明,`Date.length`(構造函數`Date`可以接受多少個參數)是`Date`自身的屬性,`Date.toString`是繼承的屬性。 另外,`hasOwnProperty`方法是 JavaScript 之中唯一一個處理對象屬性時,不會遍歷原型鏈的方法。 ## in 運算符和 for...in 循環 `in`運算符返回一個布爾值,表示一個對象是否具有某個屬性。它不區分該屬性是對象自身的屬性,還是繼承的屬性。 ```javascript 'length' in Date // true 'toString' in Date // true ``` `in`運算符常用于檢查一個屬性是否存在。 獲得對象的所有可遍歷屬性(不管是自身的還是繼承的),可以使用`for...in`循環。 ```javascript var o1 = { p1: 123 }; var o2 = Object.create(o1, { p2: { value: "abc", enumerable: true } }); for (p in o2) { console.info(p); } // p2 // p1 ``` 上面代碼中,對象`o2`的`p2`屬性是自身的,`p1`屬性是繼承的。這兩個屬性都會被`for...in`循環遍歷。 為了在`for...in`循環中獲得對象自身的屬性,可以采用`hasOwnProperty`方法判斷一下。 ```javascript for ( var name in object ) { if ( object.hasOwnProperty(name) ) { /* loop code */ } } ``` 獲得對象的所有屬性(不管是自身的還是繼承的,也不管是否可枚舉),可以使用下面的函數。 ```javascript function inheritedPropertyNames(obj) { var props = {}; while(obj) { Object.getOwnPropertyNames(obj).forEach(function(p) { props[p] = true; }); obj = Object.getPrototypeOf(obj); } return Object.getOwnPropertyNames(props); } ``` 上面代碼依次獲取`obj`對象的每一級原型對象“自身”的屬性,從而獲取`obj`對象的“所有”屬性,不管是否可遍歷。 下面是一個例子,列出`Date`對象的所有屬性。 ```javascript inheritedPropertyNames(Date) // [ // "caller", // "constructor", // "toString", // "UTC", // ... // ] ``` ## 對象的拷貝 如果要拷貝一個對象,需要做到下面兩件事情。 - 確保拷貝后的對象,與原對象具有同樣的原型。 - 確保拷貝后的對象,與原對象具有同樣的實例屬性。 下面就是根據上面兩點,實現的對象拷貝函數。 ```javascript function copyObject(orig) { var copy = Object.create(Object.getPrototypeOf(orig)); copyOwnPropertiesFrom(copy, orig); return copy; } function copyOwnPropertiesFrom(target, source) { Object .getOwnPropertyNames(source) .forEach(function (propKey) { var desc = Object.getOwnPropertyDescriptor(source, propKey); Object.defineProperty(target, propKey, desc); }); return target; } ``` 另一種更簡單的寫法,是利用 ES2017 才引入標準的`Object.getOwnPropertyDescriptors`方法。 ```javascript function copyObject(orig) { return Object.create( Object.getPrototypeOf(orig), Object.getOwnPropertyDescriptors(orig) ); } ``` ## 參考鏈接 - Dr. Axel Rauschmayer, [JavaScript properties: inheritance and enumerability](http://www.2ality.com/2011/07/js-properties.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>

                              哎呀哎呀视频在线观看