關於面向對象的幾種模式和個人理解

關於面向對象的幾種模式和個人理解。

  • 創建對象最初方式
//object構造函數:
var person = new object();
person.name = "lisi";
person.age = 25;
//字面量形式:
var person = {
    name:'lisi',
    age:25
}

缺點:使用同一個接口創建很多對象,會產生大量的重複代碼。
爲了解決這種問題,推出了工廠模式

  • 工廠模式
function createPerson(name, age, job){
    var o = new Object();
    o.name = name;
    o.age = age;
    o.job = job;
    o.sayName = function(){
        alert(this.name);
    };
    return o;
}
var person1 = createPerson("Nicholas", 29, "Software Engineer");
var person2 = createPerson("Greg", 27, "Doctor");

缺點:工廠模式雖然解決了創建多個相似對象的問題,但卻沒有解決對象識別問題(即怎麼知道一個對象的類型)
於是,又推出了構造函數模式

  • 構造函數模式
function Person(name, age, job){
    this.name = name;
    this.age = age;
    this.job = job;
    this.sayName = function(){
        alert(this.name);
    };
}
var person1 = new Person("Nicholas", 29, "Software Engineer");
var person2 = new Person("Greg", 27, "Doctor");

不同之處:

  • 沒有顯式創建對象;
  • 直接將屬性和方法賦給了this對象;
  • 沒有return語句

缺點:使用構造函數的主要問題,就是每個方法都要在每個實例上重新創建一次。並且不同函數上的同名函數是不相等的,以下代碼證明這一點:

alert(person1.sayName == person2.sayName); //false

然而,創建兩個完全相同任務的function實例的確沒有必要,況且有this對象在,根本不用再執行代碼前就把函數綁定到對象上面。因此,大家可以向下面這樣,通過把函數定義轉移到構造函數外部來解決這個問題

function Person(name, age, job){
    this.name = name;
    this.age = age;
    this.job = job;
    this.sayName = sayName;
}
function sayName(){
    alert(this.name);
}
var person1 = new Person("Nicholas", 29, "Software Engineer");
var person2 = new Person("Greg", 27, "Doctor");

這樣確實解決了兩個函數做同一件事的問題,但是新的問題又來了:在全局作用局下只爲某個對象定義一個函數,這讓全局作用域有點名副其實。而且更讓人無法接受的是:如果對象需要定義很多的方法,那麼就要定義很多的全局函數,於是,我們這個自定義的引用類型就毫無封裝性可言了。
於是,又推出了原型模式

  • 原型模式
function Person(){}
Person.prototype.name = "Nicholas";
Person.prototype.age = 29;
Person.prototype.job = "Software Engineer";
Person.prototype.sayName = function(){
    alert(this.name);
};
var person1 = new Person();
person1.sayName(); //"Nicholas"
var person2 = new Person();
person2.sayName(); //"Nicholas"
alert(person1.sayName == person2.sayName); //true

通過構造函數方式創建新對象,與構造函數不同的是,這些屬性和方法都是可以共享的。


補充
更簡單的原型語句:

function Person(){}
Person.prototype = {
    name : "Nicholas",
    age : 29,
    job: "Software Engineer",
    sayName : function () {
        alert(this.name);
    }
};

  • 最終版============》組合使用構造函數和原型模式
function Person(name, age, job){
    this.name = name;
    this.age = age;
    this.job = job;
    this.friends = ["Shelby", "Court"];
}
Person.prototype = {
    constructor : Person,
    sayName : function(){
        alert(this.name);
    }
}
var person1 = new Person("Nicholas", 29, "Software Engineer");
var person2 = new Person("Greg", 27, "Doctor");
person1.friends.push("Van");
alert(person1.friends); //"Shelby,Count,Van"
alert(person2.friends); //"Shelby,Count"
alert(person1.friends === person2.friends); //false
alert(person1.sayName === person2.sayName); //true

在這個實例中,實例屬性都是構造函數中定義的,而由所有實例共享的屬性constructor和方法sayName()則是在原型中定義的。而修改person1中的friends(向其中添加一個新的字符串),並不會影響到person2.friends,因爲他們分別引用了不用的數組.

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