JavaScript 是一門集成了函數編程和麪向對象編程的動態語言。它的對象是一個容器,封裝了屬性(property)和方法(method)。JavaScript的面向對象實現不是基於類,而是基於構造函數(constructor)和原型鏈(prototype)實現的。
一.概述
- Object.getPrototypeOf()方法? 解答: 獲取參數對象的原型對象。具體見: Object.getPrototypeOf()
- Object.setPrototypeOf()方法? 解答:設置參數對象的原型對象。具體見: Object.setPrototypeOf()
- Object.create()方法? 解答:以某個對象爲原型對象創建一個新對象。具體見: Object.create()
- Object.prototype.isPrototypeOf()方法? 解答: 實例對象的isPrototypeOf方法,用來判斷該對象是否爲參數對象的原型。具體見: Object.prototype.isPrototypeOf()
- Object.getOwnPropertyNames()和Object.keys()方法的區別? 解答:①:Object.getOwnPropertyNames方法返回一個數組,成員是參數對象本身的所有屬性的鍵名,不包含繼承的屬性鍵名。②:Object.keys()只獲取那些可以遍歷的屬性。具體見: Object.getOwnPropertyNames()和Object.keys()
- hasOwnProperty()方法? 解答:用於判斷某個屬性定義在對象自身,還是定義在原型鏈上。具體見: hasOwnProperty()
- in 運算符和 for…in 循環方法? 解答:in查詢一個對象是否具有某個屬性。包括自身的屬性和繼承屬性。 for…in 遍歷對象所有可遍歷屬性。具體見: in 運算符和 for…in 循環
二.Object.getPrototypeOf()
1.釋義
-
Object.getPrototypeOf
方法返回參數對象的原型。這是獲取原型對象的標準方法。//實例對象f的原型是F.prototype var F = function () {}; var f = new F(); Object.getPrototypeOf(f) === F.prototype // true
2.特殊原型對象
-
下面是幾種特殊對象的原型。
// 空對象的原型是 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()
1.釋義
-
Object.setPrototypeOf
方法爲參數對象設置原型,返回該參數對象。它接受兩個參數,第一個是現有對象,第二個是原型對象。//Object.setPrototypeOf方法將對象a的原型,設置爲對象b,因此a可以共享b的屬性 var a = {}; var b = {x: 1}; Object.setPrototypeOf(a, b); Object.getPrototypeOf(a) === b // true a.x // 1
2.使用
new
命令可以使用Object.setPrototypeOf
方法模擬//第一步,將一個空對象的原型設爲構造函數的prototype屬性(上例是F.prototype);第二步,將構造函數內部的this綁定這個空對象,然後執行構造函數,使得定義在this上面的方法和屬性(上例是this.foo),都轉移到這個空對象上。 var F = function () { this.foo = 'bar'; }; var f = new F(); // 等同於 var f = Object.setPrototypeOf({}, F.prototype); F.call(f);
四.Object.create()
1.釋義
-
釋義:
Object.create
方法,接受一個原型對象的參數,使用對象來創建一個實例對象。該實例完全繼承參數對象的屬性。 -
實質:
Object.create
方法的實質是新建一個空的構造函數B,然後讓B.prototype屬性指向參數對象A,最後返回一個B的實例,從而實現讓該實例繼承A的屬性。
//Object.create方法以A對象爲原型,生成了B對象。B繼承了A的所有屬性和方法。
// 原型對象
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
```
2.注意
-
使用
Object.create
方法的時候,必須提供對象原型,即參數不能爲空,或者不是對象,否則會報錯。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
方法生成的新對象,動態繼承了原型。在原型上添加或修改任何方法,會立刻反映在新對象之上。//修改對象原型obj1會影響到實例對象obj2 var obj1 = { p: 1 }; var obj2 = Object.create(obj1); obj1.p = 2; obj2.p // 2
-
Object.create
方法生成的對象,繼承了它的原型對象的構造函數。function A() {} var a = new A(); var b = Object.create(a); b.constructor === A // true b instanceof A // true
3.使用
-
如下三種創建的方式等價。
var obj1 = Object.create({}); var obj2 = Object.create(Object.prototype); var obj3 = new Object();
-
如果想要生成一個不繼承任何屬性(比如沒有
toString
和valueOf
方法)的對象,可以將Object.create
的參數設爲null
。var obj = Object.create(null); obj.valueOf() // TypeError: Object [object Object] has no method 'valueOf'
五.Object.prototype.isPrototypeOf()
1.釋義
-
實例對象的isPrototypeOf方法,用來判斷該對象是否爲參數對象的原型。
//一. o1和o2都是o3的原型。這表明只要實例對象處在參數對象的原型鏈上,isPrototypeOf方法都返回true var o1 = {}; var o2 = Object.create(o1); var o3 = Object.create(o2); o2.isPrototypeOf(o3) // true o1.isPrototypeOf(o3) // true //二. 由於Object.prototype處於原型鏈的最頂端,所以對各種實例都返回true,只有直接繼承自null的對象除外 Object.prototype.isPrototypeOf({}) // true Object.prototype.isPrototypeOf([]) // true Object.prototype.isPrototypeOf(/xyz/) // true Object.prototype.isPrototypeOf(Object.create(null)) // false
六.Object.prototype.proto
1.釋義
- 實例對象的__proto__屬性(前後各兩個下劃線),返回該對象的原型。該屬性可讀寫。但是不建議使用,因爲只能在瀏覽器環境下使用。
七.Object.getOwnPropertyNames()和Object.keys()
1.Object.getOwnPropertyNames()
-
Object.getOwnPropertyNames
方法返回一個數組,成員是參數對象本身的所有屬性的鍵名,不包含繼承的屬性鍵名。Object.getOwnPropertyNames(Date) // ["parse", "arguments", "UTC", "caller", "name", "prototype", "now", "length"]
2.Object.keys()
-
Object.keys()
只獲取那些可以遍歷的屬性。Object.keys(Date) // []
八.hasOwnProperty()
-
對象實例的hasOwnProperty方法返回一個布爾值,用於判斷某個屬性定義在對象自身,還是定義在原型鏈上。
-
hasOwnProperty方法是 JavaScript 之中唯一一個處理對象屬性時,不會遍歷原型鏈的方法。
Date.hasOwnProperty('length') // true Date.hasOwnProperty('toString') // false
九.in 運算符和 for…in 循環
1.in 運算符
-
in
運算符返回一個布爾值,表示一個對象是否具有某個屬性。包括自身的屬性和繼承屬性。'length' in Date // true 'toString' in Date // true
2.for...in
循環
-
獲得對象的所有可遍歷屬性(不管是自身的還是繼承的),可以使用
for...in
循環。 -
爲了在
for...in
循環中獲得對象自身的屬性,可以採用hasOwnProperty
方法判斷一下。for ( var name in object ) { if ( object.hasOwnProperty(name) ) { /* loop code */ } }
-
獲得對象的所有屬性(不管是自身的還是繼承的,也不管是否可枚舉),可以使用下面的函數。
function inheritedPropertyNames(obj) { var props = {}; while(obj) { //獲取本對象的屬性key Object.getOwnPropertyNames(obj).forEach(function(p) { props[p] = true; }); //獲取本對象的原型對象重新賦值給obj,當遍歷到頂層原型對象null時候,跳出循環 obj = Object.getPrototypeOf(obj); } return Object.getOwnPropertyNames(props); } //使用 inheritedPropertyNames(Date) // [ // "caller", // "constructor", // "toString", // "UTC", // ... // ]
十.獲取原型對象的比較
1.獲取原型對象
-
獲取實例對象obj的原型對象,有三種方法:
obj.__proto__
,obj.constructor.prototype
,Object.getPrototypeOf(obj)
,推薦使用第三種。//驗證三種方式等價 var obj = new Object(); obj.__proto__ === Object.prototype // true obj.__proto__ === obj.constructor.prototype // true
十一.對象的拷貝
1.拷貝一個對象需要滿足2個條件
-
一個是確保拷貝後的對象,與原對象具有同樣的原型。
-
另一個是確保拷貝後的對象,與原對象具有同樣的實例屬性。
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新方式
S2017 才引入標準的Object.getOwnPropertyDescriptors方法