1. 程式人生 > >JavaScript創建對象的幾種方式總結

JavaScript創建對象的幾種方式總結

引用 常用 添加 耦合 取代 共享 fun 支持 高程

  ECMA把對象定義為:無序屬性的集合,其屬性可以包含基本值、對象或者函數。

1. 使用Object構造函數創建對象

  創建自定義對象的最簡單的方式就是創建一個Object的實例,然後再為它添加屬性和方法。

//通過Object構造函數的實例創建對象
var person = new Object();
//添加屬性和方法
person.name = "guo";
person.age = ‘24‘;
person.sayName = function(){
    console.log(this.name);
};
//訪問屬性的兩種方式:點表示法和方括號表示法
console.log(person.name);  //
"guo" console.log(person[‘age‘]); //24 person.sayName(); //"guo"

2. 使用對象字面量創建一個對象

//使用對象字面量創建一個對象
var person = {
    name : "guo",
    age : 24,
    sayName : function(){
        console.log(this.name);
    }
};
console.log(person.name);  //"guo"
console.log(person[‘age‘]); //24
person.sayName();  //
"guo"

3.工廠模式 

  雖然Object構造函數或者對象字面量都可以用來創建單個對象,但這些方式有個明顯的缺點:使用同一個接口創建對象,會產生大量的重復代碼。為了解決這個問題,提出工廠模式。

//使用工廠模式創建對象,返回帶有屬性和方法的person對象
function createPerson(name, age){
    var o = new Object();
    o.name = name;
    o.age = age;
    o.sayName = function(){
        console.log(this.name);
    };
    
return o; } var person1 = createPerson("guo", 24); person1.sayName(); //"guo"

4.使用自定義構造函數模式創建對象

// 使用自定義構造函數模式創建對象(作為構造函數的函數首字母要大寫,以區別其它函數)
function Person(name,age){
    this.name=name;
    this.age=age;
    this.sayName=function(){
        console.log(this.name);
    };
}

var person1 = new Person("guo", 24);
person1.sayName(); //"guo”

拓展:要創建Person的新實例,必須使用new操作符。那麽,new操作符具體幹了些什麽呢?

(1)創建一個新(空)對象

(2)將構造函數的作用域賦給新對象(因為this就指向了這個新對象)

(3)執行構造函數中的代碼(為這個新對象添加屬性)

(4)返回新對象

構造函數和其他函數的唯一區別:就在於調用它們的方式不同。任何函數,只要通過new操作符來調用,那它就可以作為構造函數;而任何函數,如果不通過new操作符來調用,那它跟普通函數也不會有什麽區別。這種方式有個缺陷是,上面例子中,sayName這個方法,它的每個實例都是指向不同的函數實例,而不是同一個。即不同實例上的同門函數是不相等的

  為了解決這個問題,提出了原型模式創建對象。

5.使用原型模式創建對象

//使用原型模式創建對象(解決了構造函數中的函數無法復用問題)
function Person(){
}

Person.prototype = {  //對象字面量語法 重寫原型對象
    constructor : Person,   
    name : "guo",
    age : 24,
    friends:["liu","li"],
    sayName:function(){
        console.log(this.name);
    }
};
//創建實例1
var person1 = new Person();
person1.friends.push("yang"); 
console.log(person1.friends);  //[ ‘liu‘, ‘li‘, ‘yang‘ ]
//創建實例2
var person2 = new Person(); 
console.log(person2.friends);  //[ ‘liu‘, ‘li‘, ‘yang‘ ]  //原型模式的缺陷

person1.sayName(); //"guo"
person2.sayName(); //"guo"

  這裏我們發現了一個問題,而是原型模式的缺陷,上面例子中,person1改變數組的值,直接影響了person2中friends數組的值,這是我們不希望看到的。

  原型模式最大的問題是由共享的本質所導致的,原型中所有的屬性是被所有實例共享的。對於引用類型的值,也出現了實例共享問題。

  為了解決這個問題,提出了組合使用原型模式和構造函數創建對象。

6.組合使用構造函數和原型模式創建對象

  顧名思義,構造函數用於定義實例屬性,而原型模式用於定義方法和共享的屬性。

//組合使用原型模式和構造函數創建對象(使用最廣泛、認同度最高)
//構造函數用於定義實例屬性,而原型模式用於定義方法和共享的屬性
function Person(name,age){
    this.name = name;
    this.age = age;
  this.friends = ["liu","li"];
}
Person.prototype = {
    constructor : Person,
    sayName : function(){
        console.log(this.name);
    }
}
var person1 = new Person("guo", 24);
var person2 = new Person("zhu", 30);
person1.friends.push("yang");

console.log(person1.friends);  //[ ‘liu‘, ‘li‘, ‘yang‘ ]
console.log(person2.friends);  //[ ‘liu‘, ‘li‘ ]
person1.sayName();//"guo"
person2.sayName();//"zhu"

7.動態原型模式

//動態原型模式(具有更好的封裝性)
function Person(name, age){
    //屬性
    this.name = name;
    this.age = age;
    this.friends = ["liu","li"];
    //方法
    if(typeof this.sayName !="function"){
        Person.prototype.sayName=function(){
            console.log(this.name);
        }; 
    }
}

var person1 = new Person("guo", 24);
console.log(person1.friends);  //[ ‘liu‘, ‘li‘ ]
person1.sayName(); //"guo"

  另外還有兩個創建對象的方法,寄生構造函數模式穩妥構造函數模式。由於這兩個函數不是特別常用,這裏就不給出具體代碼了。有興趣可以查看 js高程P160-162

總結

  ECMAScript 支持面向對象(OO)編程,但不使用類或者接口。對象可以在代碼執行過程中創建和增強,因此具有動態性而非嚴格定義的實體。在沒有類的情況下,可以采用下列模式創建對象。

(1)工廠模式,使用簡單的函數創建對象,為對象添加屬性和方法,然後返回對象。這個模式後來被構造函數模式所取代。

(2)構造函數模式,可以創建自定義引用類型,可以像創建內置對象實例一樣使用new 操作符。不過,構造函數模式也有缺點,即它的每個成員都無法得到復用,包括函數。由於函數可以不局限於任何對象(即與對象具有松散耦合的特點),因此沒有理由不在多個對象間共享函數。

(3)原型模式,使用構造函數的prototype 屬性來指定那些應該共享的屬性和方法。組合使用構造函數模式和原型模式時,使用構造函數定義實例屬性,而使用原型定義共享的屬性和方法。

JavaScript創建對象的幾種方式總結