1. 程式人生 > >面向物件(建立物件)--建構函式模式02

面向物件(建立物件)--建構函式模式02

上一篇工廠模式中有一個例子

現在建立自定義的建構函式,從而定義自定義物件型別的屬性和方法。例如,可以使用建構函式模式將上面的例子重寫如下 

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

比較會發現3個不同之處

要建立 Person 的新例項,必須使用 new 操作符。以這種方式呼叫建構函式實際上會經歷以下 4個步驟: (1) 建立一個新物件; (2) 將建構函式的作用域賦給新物件(因此 this 就指向了這個新物件); (3) 執行建構函式中的程式碼(為這個新物件新增屬性); (4) 返回新物件。

  1. 沒有顯式地建立
  2. 直接將屬性和方法賦給了 this 物件
  3. 沒有 return 語句

優點: 建立自定義的建構函式意味著將來可以將它的例項標識為一種特定的型別;而這正是建構函式模式勝過工廠模式的地方。也就是說,在這個例子中,我們可以知道person1 和 person2 是Object 的例項。

1.將建構函式當做函式 建構函式與其他函式的唯一區別,就在於呼叫它們的方式不同。例如,前面例子中定義的 Person()函式可以通過下列任何一種方式來呼叫。
// 當作建構函式使用
var person = new Person("Nicholas", 29, "Software Engineer"); 
person.sayName(); //"Nicholas" 
// 作為普通函式呼叫
Person("Greg", 27, "Doctor"); // 新增到 window 
window.sayName(); //"Greg" 
// 在另一個物件的作用域中呼叫
var o = new Object(); 
Person.call(o, "Kristen", 25, "Nurse"); 
o.sayName(); //"Kristen" 
2.建構函式的問題 在前面的例子中,person1 和 person2 都有一個名為 sayName()的方法,但那兩個方法不是同一個 Function 的例項。然而,建立兩個完成同樣任務的 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"); 

可是新問題又來了:在全域性作用域中定義的函式實際上只能被某個物件呼叫,這讓全域性作用域有點名不副實。而更讓人無法接受的是:如果物件需要定義很多方法,那麼就要定義很多個全域性函式,於是我們這個自定義的引用型別就絲毫沒有封裝性可言了。