new Object()、Object.create()、{}三種對象創建方式的區別

new Object():

  new運算符創建一個用戶定義的對象類型的實例或者具有構造函數的內置對象的實例。new關鍵字會進行:

    1、創建一個空的JavaScript對象({})

    2、鏈接該對象(設置該對象的構造函數)到另一個對象

    3、將1中新創建的對象作爲this的上下文

    4、如果該函數沒有返回對象,就會返回this

當你執行
var o = new Foo();

實際上執行了
var o = new Object();
o.__proto__ = Foo.prototype;
Foo.call(o);

 

  desc:

    1、通過編寫函數來定義對象類型

    2、通過new來創建對象實例

  創建一個對象類型,需要創建一個指定其名稱和屬性的函數;對象的屬性可以指向其它對象

 

  當代碼  new Foo(...)  執行的時候

    1、一個繼承自Foo.prototype的新對象被創建

    2、使用指定的參數調用構造函數Foo,並將this綁定到新創建的對象。new Foo等同於Foo(),也就是沒有指定參數列表,Foo不帶任何參數調用的情況

    3、由構造函數返回的對象就是new表達式的結果。如果構造函數沒有顯式返回一個對象,就是用步驟一創建的對象。(一般情況下,構造函數不返回值,但是用戶可以選擇主動返回對象,來覆蓋正常的對象創建步驟)

 

  如果沒有使用new運算符,構造函數會像其它的常規函數一樣被調用,並不會創建一個對象。這種情況下,this的指向也是不一樣的。

 

Object.create():

  創建一個新對象,使用現有的對象來提供新創建的對象的__proto__

const person = {
  isHuman: false,
  printIntroduction: function () {
    console.log(`My name is ${this.name}. Am I human? ${this.isHuman}`);
  }
};

const me = Object.create(person);

me.name = "Matthew"; // "name" 這個屬性只被寫在me上, 沒有被寫在"person"上
me.isHuman = true; // 繼承的屬性可被重寫

me.printIntroduction();
// expected output: "My name is Matthew. Am I human? true"

  語法:Object.create(proto, [propertiesObject])

    proto:新創建對象的原型對象

    propertiesObject:可選的,如果沒有指定爲undefined,要添加到新創建對象的可枚舉屬性(即自身定義的屬性,而不是其原型鏈上的枚舉屬性)對象的屬性描述符以及相應的屬性名稱。這些屬性相對應Object.definedProperties()的第二個參數

  返回值:一個新對象帶着指定的原型對象和屬性

  例外:如果propertiesObject參數是null或者是非原始包裝對象,就會拋出一個TypeError異常。

// Shape - 父類(superclass)
function Shape() {
  this.x = 0;
  this.y = 0;
}

// 父類的方法
Shape.prototype.move = function(x, y) {
  this.x += x;
  this.y += y;
  console.info('Shape moved.');
};

// Rectangle - 子類(subclass)
function Rectangle() {
  Shape.call(this); // call super constructor.
}

// 子類續承父類
Rectangle.prototype = Object.create(Shape.prototype);
Rectangle.prototype.constructor = Rectangle;

var rect = new Rectangle();

console.log('Is rect an instance of Rectangle?',rect instanceof Rectangle); // true
console.log('Is rect an instance of Shape?',rect instanceof Shape); // true
rect.move(1, 1); // Outputs, 'Shape moved.'

 

  如果要是希望能夠繼承多個對象,就可以使用混入的方式:

function MyClass() {
     SuperClass.call(this);
     OtherSuperClass.call(this);
}

// 繼承一個類
MyClass.prototype = Object.create(SuperClass.prototype);
// 混合其它
Object.assign(MyClass.prototype, OtherSuperClass.prototype);
// 重新指定constructor
MyClass.prototype.constructor = MyClass;

MyClass.prototype.myMethod = function() {
     // do a thing
};

 

  使用Object.create的propertiesObject參數

var o;

// 創建一個原型爲null的空對象
o = Object.create(null);


o = {};
// 以字面量方式創建的空對象就相當於:
o = Object.create(Object.prototype);


o = Object.create(Object.prototype, {
  // foo會成爲所創建對象的數據屬性
  foo: { 
    writable:true,
    configurable:true,
    value: "hello" 
  },
  // bar會成爲所創建對象的訪問器屬性
  bar: {
    configurable: false,
    get: function() { return 10 },
    set: function(value) {
      console.log("Setting `o.bar` to", value);
    }
  }
});


function Constructor(){}
o = new Constructor();
// 上面的一句就相當於:
o = Object.create(Constructor.prototype);
// 當然,如果在Constructor函數中有一些初始化代碼,Object.create不能執行那些代碼


// 創建一個以另一個空對象爲原型,且擁有一個屬性p的對象
o = Object.create({}, { p: { value: 42 } })

// 省略了的屬性特性默認爲false,所以屬性p是不可寫,不可枚舉,不可配置的:
o.p = 24
o.p
//42

o.q = 12
for (var prop in o) {
   console.log(prop)
}
//"q"

delete o.p
//false

//創建一個可寫的,可枚舉的,可配置的屬性p
o2 = Object.create({}, {
  p: {
    value: 42, 
    writable: true,
    enumerable: true,
    configurable: true 
  } 
});

 

 

 

{}:

  是JavaScript對象字面量創建的形式,其本質和new Object() 並無區別,默認都是繼承了Object對象上的prototype

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章