JS物件導向設計-建立物件

LittlePANDA發表於2019-06-23

Object建構函式和物件字面量都可以用來建立單個物件,但是在建立多個物件時,會產生大量重複程式碼.

1.工廠模式

工廠模式抽象了建立具體物件的過程.由於ECMAScript無法建立類,我們用函式來封裝以特定介面建立物件的細節.

function createPerson(name, age, job) {
    var o = new Object();
    o.name = name;
    o.age = age;
    o.job = job;
    o.sayName = function() {
        console.log(this.name);
    }
    return o;
}

// 根據接收到的引數,構建一個包含三個屬性一個方法的物件,並返回
var person1 = createPerson("zhu", 26, "FE");

ps. 工廠模式解決了建立多個相似物件的問題,卻無法識別物件(物件的型別)

2.建構函式模式

用來建立特定型別的物件,比如Object/Array這樣的原生建構函式,或者自定義建構函式(可以自定義物件型別的屬性和方法).

/* 1.沒有顯示建立物件
*  2.直接將屬性和方法賦值給this物件
*  3.沒有return語句
*  4.首字母大寫(區別於ECMAScript中其他函式,建構函式本身也是函式,只不過可以建立物件)
*/
function Person(name, age, job) {
    this.name = name;
    this.age = age;
    this.job = job;
    this.sayName = function() {
        console.log(this.name);
    }
}

// 必須使用new操作符
var person1 = new Person("zhu", 26, "FE");
var person2 = new Person("liu", 23, "JAVA");

2.1 呼叫該總種建構函式會經歷四個步驟

  1. 建立一個新物件
  2. 將建構函式的作用域賦給新物件(因此this就指向了這個新物件)
  3. 執行建構函式中的程式碼(為這個新物件新增屬性)
  4. 返回新物件

2.2 物件型別

  1. person1,person2分別儲存著Person的一個不同例項,兩個物件都有constructor(建構函式)屬性指向Person.
    js person1.constructor == Person, person2.constructor == Person // true
  2. person1,person2既是Object例項也是Person例項.

    // 所有物件均繼承自Object
    person1 instanceof Object, person1 instanceof Person // true
    person2 instanceof Object, person2 instanceof Person // true

    ps. 建立自定義建構函式意味著可以將它的例項標識為一種特定的型別.

2.3 將建構函式當作函式

建構函式與普通函式的區別在於呼叫它們的方式不同,只要通過new操作符呼叫,它就可以作為建構函式.

// 當作建構函式使用,使用new操作符來建立一個新物件.
var person = new Person("zhu", 26, "FE");
person.sayName();

// 作為普通函式呼叫,屬性和方法都被新增到window物件.
// 在全域性作用域中呼叫一個函式時,this物件總是指向Global物件(在瀏覽器中就是window物件)
Person("zhu", 26, "FE");
window.sayName();

// 使用call()或者apply()在某個特定物件的作用域中呼叫
var o = new Object();
Person.call(o, "zhu", 26, "FE");
o.sayName();

ps. 建構函式模式定義的建構函式是定義在Global物件中的.

2.4 建構函式的問題

每個方法都要在每個例項上重新建立一遍,person1和person2的同名sayName方法不是同一個function的例項.

ps. ECMAScript的函式是物件,因此每定義一個函式,也就例項化一個物件.即每個Person例項都包含一個不同function例項.

// 邏輯上的建構函式可以這樣定義
function Person(name, age) {
    this.name = name;
    this.age = age;
    this.sayName = new function() {
        console.log(this.name);
    }
}

沒有必要建立兩個完成同樣任務的function例項,然而將sayName提到全域性雖然解決做同一件事的問題,但是實際上只能被某個物件呼叫,而且可能需要定義很多全域性函式(無封裝性).

相關文章