js創建對象之設計模式

1. 工廠模式

function createPerson(name, age){

    var obj = new Object();

    obj.name = name;
    obj.age = age;

    obj.sayName = function(){
        console.log(this.name); // | console.log(obj.name)
    };

    return obj;
}

var p1 = createPerson("ys", 12);
var p2 = createPerson("ys", 12);
console.log(p1);         // { name: 'ys', age: 12, sayName: [Function] }
console.log(p2);         // { name: 'ys', age: 12, sayName: [Function] }
console.log(p1 == p2);   //false

特點:

  • 內部創建對象,外部返回,相當於調用函數,
  • 對象無類型(比如其他oo語言,new一個對象,那個這個對象的構造函數就是對象類型)

2.構造函數模式

function Person(name, age){
    this.name = name;
    this.age = age;

    this.sayName = function(){
        console.log(this.name);
    };
}

var p1 = new Person("ys", 12);
var p2 = new Person("ys", 12);
console.log(p1);                        // { name: 'ys', age: 12, sayName: [Function] }
console.log(p2);                        // { name: 'ys', age: 12, sayName: [Function] }
console.log(p1 == p2);                  //false
console.log(p1 instanceof Person);      //true
console.log(p2 instanceof Person);      //true
console.log(p1 instanceof Object);      //true
console.log(p2 instanceof Object);      //true

console.log(p1.constructor == Person);  //true  /*constructor屬性爲構造函數屬性,指向構造函數Person*/
console.log(p2.constructor == Person);  //true

特點:

  • 通過該模式創建的對象有自定義類型Person, 每個對象都是構造函數的實例
  • 構造函數已經不再是意義上的調用函數,而是使用了new,構造過程包括四個步驟:
    • ①創建一個新對象
    • ②將構造函數的作用域賦給新對象(因此this指向了這個新對象)
    • ③執行構造函數中的代碼(爲這個新對象添加屬性)
    • ④返回新對象

對於這樣的構造函數模式,會發現有一點瑕疵,那就是sayName函數的功能是一樣的,但是每個對象的實例都有該函數,這樣卻顯得有點冗餘,在此基礎上,進行了一些改良:

function Person(name, age){
    this.name = name;
    this.age = age;

    this.sayName = sayName;
}

function sayName(){
    console.log(this.name);
}

將公共的函數部分,提取出來,作爲全局函數,使得每個構造函數去調用他,達到了所有實例對象複用的效果。

2015-12-12 補充…
通過不斷的的學習,對構造函數模式有了新的理解,補充:

上面我寫的構造函數是用函數聲明的方式定義的,另一種方法,我們也可以用對象直接量方法聲明

var Person = function(name, age){
    this.name = name;
    this.age = age;

    this.sayName = function(){
        console.log(this.name);
    };
}

var p1 = new Person("ys", 12);
var p2 = new Person("ys", 12);
console.log(p1);                        // { name: 'ys', age: 12, sayName: [Function] }
console.log(p2);                        // { name: 'ys', age: 12, sayName: [Function] }

這樣同樣我得到了效果….但是最近看書學習,發現了一個問題,上面我這種方法(包括兩種方法 )安全嗎?
就連我之前都沒有質疑過安全性,看看下面的代碼

構造函數我就不寫了.函數,對象直接量都是一個意思…

var p1 = Person("ys", 12);
var p2 = Person("ys", 12);
console.log(p1);                        // undefined
console.log(p2);                        // undefined

我們會發現竟然是undefined,怎麼會,快找找原因….原因是他少了new這個關鍵字…
爲什麼會出現這樣的原因呢,我們正確的結果,或許一看你就會了解。

var p1 = Person("ys", 12);
var p2 = Person("ys", 12);
console.log(p1);                        // undefined
console.log(p2);                        // undefined

console.log(window.name);               //ys
console.log(window.age);                //12

原因就是沒了new這個關鍵字,對於js的new關鍵字,大家可以這樣理解:
new就是將函數內部的this的值,賦值給當前對象的this,如:this.name(實例對象) = this.name(構造函數)
當沒有new的時候,this就變爲了window,也就解釋了。

那麼問題又來了,有時候我們就是會忘記new,那這樣的構造函數就顯得不安全,這裏有一個安全的構造函數模式,可以幫到你

/*安全的構造函數模式*/
var Person = function(name, age){

    if(this instanceof Person){     
        this.name = name;
        this.age = age;

        this.sayName = function(){
            console.log(this.name);
        };
    }else{
        return new Person(name, age);
    }

}

var p1 = Person("ys", 12);
var p2 = Person("ys", 12);
console.log(p1);                        // { name: 'ys', age: 12, sayName: [Function] }
console.log(p2);                        // { name: 'ys', age: 12, sayName: [Function] }

console.log(window.name);               // undefined
console.log(window.age);                // undefined

3.原型對象模式

然後我們也覺得一個問題出現了,對於上面改良後的構造函數模式,所創建的全局函數sayName似乎成了Person構造函數的私人司機,只對於他一個人用,這樣也就失去了全局函數的價值,而且當存在諸多構造函數時候,諸多的“sayName”也是一個問題,這個時候,原型模式完美的解決了這個問題

//需要變動部分
function Person(name){
    this.name = name;
}
//永久不變部分
Person.prototype.age = 12;
Person.prototype.sayName = function(){
    console.log(this.name);
}

var p1 = new Person("ys");
var p2 = new Person("ab");
console.log(p1.sayName());              //ys
console.log(p1.age);                    //12

console.log(p2.sayName());              //ab
console.log(p2.age);                    //12

console.log(p1.sayName == p2.sayName);  //true

當創建一個函數時候,該函數存在一個prototype屬性,該屬性是一個指針,指向一個對象,這個對象是一個方法和屬性的集合,存儲公共的屬性和方法,達到所有實例共享的目的。
有全局對象的特性,區別於全局,Person構造函數的私人全局,只對它(Person)一個人生效。
當存在於對象實例時候,他們共享prototype裏面的東西。

發佈了57 篇原創文章 · 獲贊 84 · 訪問量 17萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章