創建對象的4種方式

創建對象的4種方式

  • 方式一:通過對象字面量表示法(又稱爲直接量、原始方式)。object literals
  • 方式二:通過new和構造函數Object()、String()等。
  • 方式三:用自定義構造函數來初始化新對象。
  • 方式四:通過Object.create()

方式一:通過對象字面量表示法(又稱爲直接量、原始方式)object literals

var obj = {name:"zyx456"};

對象字面量是一個名/值對列表,每個名/值對之間用逗號分隔,名和值之間用冒號分隔,最後整體用一個花括號括起來。

屬性名可以使用數值,比如5。數值屬性名會自動轉換爲字符串。

var person = {"name" : "Nicholas","age" : 29,5 : true};

屬性名一般不加引號,以下情況必須加引號:

  • 屬性名中有空格,
  • 有連字符“-”
  • 有關鍵字,比如“for”。

在ES5(以及ES3的一些實現)中,保留字可以用做不帶引號的屬性名。然而對於ES3來說,使用保留字作爲屬性名必須使用引號引起來。

例子:

var person = {
    name : "Nicholas",
    age : 29};

在ES5中,對象直接量中的最後一個屬性後的逗號可以省略,且在ES3的大部分實現中也可以忽略這個逗號,但在IE中則報錯。

使用對象字面量語法時,如果留空其花括號,則可以定義只包含默認屬性和方法的空對象。

var obj = {};

對象字面量也可以先創建,再添加屬性和方法。

var person = {};         //與new Object()相同
person.name = "Nicholas";
person.age = 29;

在通過對象字面量定義對象時,實際上不會調用Object構造函數。

對象可以嵌套對象:

例如:

var myHome={
        population : "10,000" ,
        area : "10,000" ,
        adress : {  // 屬性
                country : "China" ,
                province : "shanxi" ,
                city : "xian"
            },
        say : function(){  // 方法
                return "My hometown is very beautiful ! ";
            }
    }

//構造嵌套的對象
var SchoolData = {
    code: "0123-456-789",
    Tel: "0551-1234567",
    Fax: "0551-7654321"
};
//構造被嵌入的對象
var ZGKJDX = {
    name: "中國科技大學",
    address: "安徽·合肥",
    grade: "高等學府",
    number: "13400",
    //嵌套對象SchoolData
    data: SchoolData,
};

有一個缺點:如果我們想在其他地方創建一個同樣的對象,就得把這個對象的所有代碼都複製粘貼過去。我們需要一種能夠批量創建同樣對象的方法,而不是隻創建一個對象。

有一個問題:即無法保證屬性的順序。

添加屬性的順序可能並不是遍歷輸出屬性時的順序。

例如

var o = {}
o.a = 1
o.b = 2
o.c = 3
for(key in o) console.log(key); // expected a,b,c - but not guaranteed to be in that order

Object 對象也缺乏forEach的方法,不能對object使用通常的迭代方法。

o.forEach // undefined

方式二:通過new和構造函數Object()、String()等。

var obj = new Object();

這裏的函數稱做構造函數(constructor)。

如下所示:

var person = new Object();
person.name = "Nicholas";
person.age = 29

如果構造函數無參數,括號則不是必需的。

因此可以採用下面的形式重寫上面的兩行代碼:

var oObject = new Object;
var oStringObject = new String;
var str  = new String();
console.log(str); // 輸出的是 String{length:0,[[PrimitiveValue]]:""}
console.log(typeof str);//object;

結果:

clipboard.png

JS原始類型都包含內置構造函數。例如:

var o = new Object();           // 創建一個空對象,和{}一樣
var a = new Array();            // 創建一個空數組,和[]一樣
var d = new Date();             // 創建一個表示當前時間的Date對象
var r = new RegExp("js");       //創建一個可以進行模式匹配的EegExp對象

在JS中,通過 new 運算符來作用與一個函數,實質上會發生這樣的過程:

首先,創建一個空對象,然後用函數的apply方法,將這個空對象傳入作爲 apply 的第一個參數,作爲上下文參數。也就是this的指向。

var triangle = new Shape("triangle");
    //上一句相當於下面的代碼
var triangle = {};
Shape.apply(triangle, ["triangle"]);

方式三:用自定義構造函數來初始化新對象。

function A(o){
this.name = "moyu"
}
let obj = new a();

clipboard.png

例子:

function person(firstname,lastname,age,eyecolor){
    this.firstname=firstname;
    this.lastname=lastname;
    this.age=age;
    this.eyecolor=eyecolor;
}
var myFather=new person("Bill","Gates",56,"blue");
var myMother=new person("Steve","Jobs",48,"green");

在自定義構造函數的內部定義對象的方法:

function person(firstname,lastname,age,eyecolor)
{
    this.firstname=firstname;
    this.lastname=lastname;
    this.age=age;
    this.eyecolor=eyecolor;
 
    this.changeName=changeName;
    function changeName(name)
    {
        this.lastname=name;
    }
}

changeName() 函數 name 的值賦給 person 的 lastname 屬性。

myMother.changeName("Ballmer");

方式四:通過Object.create()

Object.create()是一個靜態函數,而不是提供給某個對象實例調用的方法。

var o1 = Object.create({x:1, y:2}); // o1繼承了屬性x和y

可以通過任意原型創建新對象(換句話說,可以繼承任意對象)。

第一個參數是這個新對象的原型。

第二個參數屬性描述符對象propertiesObject,用於對對象的屬性進行進一步描述。可選。

屬性描述符對象中的屬性,默認不可枚舉,是繼承的屬性。

如果propertiesObject指定爲 undefined,那麼是空對象{}。

如果是null或非原始包裝對象,則拋出一個 TypeError 異常。

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);
        }
    }
});

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

例子:

var obj = Object.create({}, {p: {value: 42}});
Object.values(obj); // => []

上面代碼中,Object.create()方法的第二個參數添加的對象屬性(屬性p),如果不顯式聲明,默認是不可遍歷的,因爲p是繼承的屬性,而不是對象自身的屬性。

可以通過傳入參數null來創建一個沒有原型的新對象,但通過這種方式創建的對象不會繼承任何東西,甚至不包括基礎方法,比如toString(),也就是說,它將不能和“+”運算符一起正常工作:

var o2 = Object.create(null);      //o2不繼承任何屬性和方法

如果想創建一個普通的空對象(比如通過{}或new Object()創建的對象),需要傳入Object.prototype:

var o3 = Object.create(Object.prototype);  //o3和{}和new Object()一樣

例子:通過原型繼承創建一個新對象。

inherit() 返回了一個繼承自原型對象p的新對象。

這裏使用ES5中的Object.create()函數(如果存在的話)。

如果不存在Object.create(),則退化使用其他方法。

function inherit(p) {
        if (p == null) throw TypeError();       // p是一個對象,但不能是null
        if (Object.create)   return Object.create(p);   // 如果Object.create()存在,直接使用它
        var t = typeof p;                       // 否則進行進一步檢測
        if (t !== "object" && t !== "function") throw TypeError();
        function f() {};                        // 定義一個空構造函數
        f.prototype = p;                        //將其原型屬性設置爲p
        return new f();                         //使用f()創建p的繼承對象
}
var o = {};    
o.x = 1;      
var p = inherit(o); // p繼承o和Object.prototype
p.y = 2;        
var q = inherit(p); 
q.z = 3;      
var s = q.toString(); 
q.x + q.y       // => 3: x和y分別繼承自o和p

注意,inherit()並不能完全代替Object.create(),它不能通過傳入null原型來創建對象,而且不能接收可選的第二個參數。

inherit()函數的其中一個用途就是防止庫函數無意間(非惡意地)修改那些不受你控制的對象。

不是將對象直接作爲參數傳入函數,而是將它的繼承對象傳入函數。

當函數讀取繼承對象的屬性時,實際上讀取的是繼承來的值。

如果給繼承對象的屬性賦值,則這些屬性只會影響這個繼承對象自身,而不是原始對象:

var o = { x: "don't change this value" };
library_function(inherit(o));   // 防止對o的意外修改
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章