JavaScript 面向對象編程繼承【四】Object 對象的相關方法

JavaScript 是一門集成了函數編程和麪向對象編程的動態語言。它的對象是一個容器,封裝了屬性(property)和方法(method)。JavaScript的面向對象實現不是基於類,而是基於構造函數(constructor)和原型鏈(prototype)實現的。

一.概述

  1. Object.getPrototypeOf()方法? 解答: 獲取參數對象的原型對象。具體見: Object.getPrototypeOf()
  2. Object.setPrototypeOf()方法? 解答:設置參數對象的原型對象。具體見: Object.setPrototypeOf()
  3. Object.create()方法? 解答:以某個對象爲原型對象創建一個新對象。具體見: Object.create()
  4. Object.prototype.isPrototypeOf()方法? 解答: 實例對象的isPrototypeOf方法,用來判斷該對象是否爲參數對象的原型。具體見: Object.prototype.isPrototypeOf()
  5. Object.getOwnPropertyNames()和Object.keys()方法的區別? 解答:①:Object.getOwnPropertyNames方法返回一個數組,成員是參數對象本身的所有屬性的鍵名,不包含繼承的屬性鍵名。②:Object.keys()只獲取那些可以遍歷的屬性。具體見: Object.getOwnPropertyNames()和Object.keys()
  6. hasOwnProperty()方法? 解答:用於判斷某個屬性定義在對象自身,還是定義在原型鏈上。具體見: hasOwnProperty()
  7. 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();
    
  • 如果想要生成一個不繼承任何屬性(比如沒有toStringvalueOf方法)的對象,可以將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.prototypeObject.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方法
    
發佈了181 篇原創文章 · 獲贊 65 · 訪問量 6萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章