javascript
JS-Object 对象的相关方法
參考文章:Object 對象的相關方法
1.Object.getPrototypeOf()
Object.getPrototypeOf方法返回參數對象的原型。這是獲取原型對象的標準方法。
- 下面代碼中,實例對象f的原型是F.prototype。
- 下面是幾種特殊對象的原型。
2.Object.setPrototypeOf()
- Object.setPrototypeOf方法為現有對象設置原型,返回該現有對象。它接受兩個參數,第一個是現有對象,第二個是原型對象。
上面代碼中,Object.setPrototypeOf方法將對象a的原型,設置為對象b,因此a可以共享b的屬性。
- new命令可以使用Object.setPrototypeOf方法模擬。
上面代碼中,new命令新建實例對象,其實可以分成兩步:
第一步,將一個空對象的原型設為構造函數的prototype屬性(上例是F.prototype),返回值為空對象{}賦值給變量f;
第二步,將構造函數內部的this綁定到這個空對象f,使得定義在this上面的方法和屬性(上例是this.foo),都轉移到這個空對象上。
3.Object.create()
生成實例對象的常用方法是,使用new命令讓構造函數返回一個實例對象。但我們怎么從一個實例對象,生成另一個實例對象呢?
- JavaScript 提供了Object.create方法,用來滿足這種需求。該方法接受一個原型對象作為參數,返回一個實例對象。該實例完全繼承原型對象的屬性。
上面代碼中,Object.create方法以A對象為原型,生成了B對象。B繼承了A的所有屬性和方法。
- 實際上,Object.create方法可以用下面的代碼代替。
上面代碼表明,Object.create方法的實質是:
(1)新建一個空的構造函數F,
(2)然后讓F.prototype屬性指向參數對象obj,
(3)最后返回一個F的實例,從而實現讓該實例繼承obj的屬性。
- 下面三種方式生成的新對象是等價的。
- 如果想要生成一個不繼承任何屬性(比如沒有toString和valueOf方法)的對象,可以將Object.create的參數設為null。
上面代碼中,對象obj的原型是null,它就不具備一些定義在Object.prototype對象上面的屬性,比如valueOf方法。
- 使用Object.create方法的時候,必須提供原型對象,即參數不能為空,或者不是對象,否則會報錯。
- Object.create方法生成的新對象,動態繼承了原型。在原型上添加或修改任何方法,會立刻反映在新對象之上。
上面代碼中,修改對象原型obj1會影響到實例對象obj2。
- 除了對象的原型,Object.create方法還可以接受第二個參數。該參數是一個屬性描述對象,它所描述的對象屬性,會添加到實例對象,作為該對象自身的屬性。
- Object.create方法生成的對象,繼承了它的原型對象的構造函數。
上面代碼中,b對象的原型是a對象,因此b繼承了a對象的構造函數A。
4.Object.prototype.isPrototypeOf()
實例對象的isPrototypeOf方法,用來判斷該對象是否為參數對象的原型。
var o1 = {}; var o2 = Object.create(o1); var o3 = Object.create(o2);o2.isPrototypeOf(o3) // true o1.isPrototypeOf(o3) // true 復制代碼上面代碼中,o1是o3**的原型,o2也是o3的原型。這表明只要實例對象處在參數對象的原型鏈上,isPrototypeOf方法都返回true。
Object.prototype.isPrototypeOf({}) // true Object.prototype.isPrototypeOf([]) // true Object.prototype.isPrototypeOf(/xyz/) // true Object.prototype.isPrototypeOf(Object.create(null)) // false 復制代碼上面代碼中,由于Object.prototype處于原型鏈的最頂端,所以對各種實例都返回true。只有直接繼承自null的對象除外。
5.Object.prototype.__proto__
實例對象的__proto__屬性(前后各兩個下劃線),返回該對象的原型。該屬性可讀寫。
- 下面代碼通過__proto__屬性,將p對象設為obj對象的原型。
-
根據語言標準,__proto__屬性只有瀏覽器才需要部署,其他環境可以沒有這個屬性。它前后的兩根下劃線,表明它本質是一個內部屬性,不應該對使用者暴露。因此,應該盡量少用這個屬性,而是應該用Object.getPrototypeof()和Object.setPrototypeOf(),進行原型對象的讀寫操作。
-
原型鏈可以用__proto__很直觀地表示。
上面代碼中,A對象和B對象的原型都是proto對象,它們都共享proto對象的print方法。也就是說,A和B的print方法,都是在調用proto對象的print方法。
6.獲取原型對象方法的比較
如前所述,__proto__屬性指向當前對象的原型對象,即構造函數的prototype屬性。
var obj = new Object();obj.__proto__ === Object.prototype // true obj.__proto__ === obj.constructor.prototype // true 復制代碼上面代碼首先新建了一個對象obj,它的__proto__屬性,指向構造函數(Object或obj.constructor)的prototype屬性。
- 因此,獲取實例對象obj的原型對象,有三種方法。
上面三種方法之中,前兩種都不可靠。
__proto__屬性只有瀏覽器才需要部署,其他環境可以不部署。
而obj.constructor.prototype在手動改變原型對象時,可能會失效。
下面代碼中,構造函數C的prototype 被改成了p,但是實例對象c的構造函數constructor的prototype卻沒有指向p。
var P = function () {}; var p = new P();var C = function () {}; C.prototype = p;//構造函數C的prototype 被改成了p var c = new C();c.constructor.prototype === p // false 復制代碼所以,在改變原型對象時,一般要同時設置constructor屬性。
C.prototype = p; C.prototype.constructor = C;var c = new C(); c.constructor.prototype === p // true 復制代碼因此,推薦使用第三種Object.getPrototypeOf方法,獲取原型對象。
7.Object.getOwnPropertyNames()
Object.getOwnPropertyNames方法返回一個數組,成員是參數對象本身的所有屬性的鍵名,不包含繼承的屬性鍵名。
Object.getOwnPropertyNames(Date) // ["parse", "arguments", "UTC", "caller", "name", "prototype", "now", "length"] 復制代碼上面代碼中,Object.getOwnPropertyNames方法返回Date所有自身的屬性名。
對象本身的屬性之中,有的是可以遍歷的(enumerable),有的是不可以遍歷的。Object.getOwnPropertyNames方法返回所有鍵名,不管是否可以遍歷。Object.keys方法只獲取那些可以遍歷的屬性。
Object.keys(Date) // [] 復制代碼上面代碼表明,Date對象所有自身的屬性,都是不可以遍歷的。
8.Object.prototype.hasOwnProperty()
對象實例的hasOwnProperty方法返回一個布爾值,用于判斷某個屬性定義在對象自身,還是定義在原型鏈上。
Date.hasOwnProperty('length') // true Date.hasOwnProperty('toString') // false 復制代碼上面代碼表明,Date.length(構造函數Date可以接受多少個參數)是Date自身的屬性,Date.toString是繼承的屬性。
另外,hasOwnProperty方法是 JavaScript 之中唯一一個處理對象屬性時,不會遍歷原型鏈的方法。
9. in 運算符和 for...in 循環
- in運算符返回一個布爾值,表示一個對象是否具有某個屬性。它不區分該屬性是對象自身的屬性,還是繼承的屬性。
in運算符常用于檢查一個屬性是否存在。
- 獲得對象的所有可遍歷屬性(不管是自身的還是繼承的),可以使用for...in循環。
上面代碼中,對象o2的p2屬性是自身的,p1屬性是繼承的。這兩個屬性都會被for...in循環遍歷。
- 為了在for...in循環中獲得對象自身的屬性,可以采用hasOwnProperty方法判斷一下。
- 獲得對象的所有屬性(不管是自身的還是繼承的,也不管是否可枚舉),可以使用下面的函數。
上面代碼依次獲取obj對象的每一級原型對象“自身”的屬性,從而獲取obj對象的“所有”屬性,不管是否可遍歷。
下面是一個例子,列出Date對象的所有屬性。
inheritedPropertyNames(Date) // [ // "caller", // "constructor", // "toString", // "UTC", // ... // ] 復制代碼10.對象的拷貝
如果要拷貝一個對象,需要做到下面兩件事情:
- 確保拷貝后的對象,與原對象具有同樣的原型。
- 確保拷貝后的對象,與原對象具有同樣的實例屬性。
下面就是根據上面兩點,實現的對象拷貝函數。
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);//通過屬性描述對象desc,定義target對象上的屬性propKeyObject.defineProperty(target, propKey, desc);});return target; } 復制代碼另一種更簡單的寫法,是利用 ES2017 才引入標準的Object.getOwnPropertyDescriptors方法。
function copyObject(orig) {return Object.create(Object.getPrototypeOf(orig),//獲取orig對象的原型對象Object.getOwnPropertyDescriptors(orig)); } 復制代碼總結
以上是生活随笔為你收集整理的JS-Object 对象的相关方法的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: information_schema系列
- 下一篇: 在Docker中运行SpringBoot