工廠模式,構造函數模式,原型模式,組合模式簡單理解

作爲編程人員一定要知道面向對象,javascript支持面向對象編程。
今天我們來簡單介紹一下創建對象的幾種模式。
我們知道創建對象常見的方式有兩種:字面量方式和new 操作符方式

字面量
var people1 = {
name:"小明"
}
new操作符
var people2 = new Object()
people2.name="小花"

儘管這兩種可以滿足我們的基本要求,但是在創建大量類似對象時候,會產生大量的重複代碼。因此我們產生了工廠模式

   function person(name,age) {
        var obj = new Object();
        obj.name = name;
        obj.age = age;
        obj.sayName = function () {
            alert(this.name)
        };
        return obj
    }
   var person1 = person('小明',12)
    console.log(person1  instanceof person)//false
    console.log(person1  instanceof Object)//true

雖然工廠模式解決了我們創建大量對象問題,但是產生了新的問題,無法確定對象的來源問題,因此我們產生了構造函數模式

function Person(name) {
    this.name = name;
    this.sayName = function () {
        console.log(this.name)
    }
}
var p1 = new Person("小明");
var p2 = new Person("小花");
console.log(p1 instanceof  Person)//true
console.log(p1 instanceof  Object)//true
console.log(p1.sayName===p2.sayName);//false
p1.sayName();
p2.sayName();

這種方式解決了對象的來源問題,但是也有問題,每生成一個實例都會創建一個function實例,因此我們改進模式,讓每個實例的方法指向同一個實例

function Person(name) {
    this.name = name;
    this.sayName = sayName
}
function sayName() {
    alert(this.name)
}
var p1 = new Person("小明");
var p2 = new Person("小花");
console.log(p1.sayName===p2.sayName)//true

但是這樣在全局作用域的方法只能被Person實例化的對象使用,而且多個方法需要創建多個全局方法,這樣封裝性很低。於是我們產生了原型模式
每個函數都有它的原型屬性,即prototype,這個屬性是一個指針,指向一個對象

 function Person() {
    };
    Person.prototype.name = "小明";
    Person.prototype.sayName = function () {
        alert(this.name)
    };
    var p1 = new Person();
    var p2 = new Person();
    console.log(p1.name);//小明
    console.log(p2.name);//小明
    console.log(p1.sayName===p2.sayName)//true
    console.log(p1 instanceof Person)//true

原型模式既解決了對象來源問題,也解決了對象公用同一方法的問題。但是原型模式也不是沒有缺點的

  function Person() {
    };
    Person.prototype.name = "小明";
    Person.prototype.family = ["小王","小張","小李"];
    Person.prototype.sayName = function () {
        alert(this.name)
    };
    var p1 = new Person();
    var p2 = new Person();

    p1.family.push("小孫")
    console.log(p1.family);//["小王", "小張", "小李", "小孫"]
    console.log(p2.family);//["小王", "小張", "小李", "小孫"]

如上所示,每個實例都繼承了原型的默認屬性,當某個實例被修改時,會改變原型的,因此,p2的family也跟隨改變,前提是修改他的屬性而不是賦值,直接給p1的family賦值是不會改變p2的。當然你也可以通過複製原型的屬性在進行操作(實際上就是賦值),但是這樣顯然不是我們想要的。

  let family = JSON.parse(JSON.stringify(p1.family))
  family.push("小孫");
  p1.family = family;
  console.log(p1.family);//["小王", "小張", "小李", "小孫"]
  console.log(p2.family);//["小王", "小張", "小李"]

於是我們再次改進,這樣出現了組合模式,構造函數模式和原型模式

function Person(name) {
    this.name = name;
    this.family = ["小王","小張","小李"];
};
Person.prototype.age = 22;
Person.prototype.sayName = function () {
    alert(this.name)
};
var p1 = new Person("小黑");
var p2 = new Person("小明");
p1.family.push("小紅");
console.log(p1.name);//小黑
console.log(p2.name);//小明
console.log(p1.age);//22
console.log(p2.age);//22
console.log(p1.family);//["小王", "小張", "小李", "小紅"]
console.log(p2.family);//["小王", "小張", "小李"]

構造函數用於定義實例屬性,原型用於定義共享的屬性和方法,這種方法也是目前最常用的自定義類型方式。既共享方法又獨立屬性

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