第二篇 關(guān)于對象

寫在前面:這次來說下 JavaScript 中對象的創(chuàng)建,文中提到的方法均較為常用,其他方法請自行百度。

2.1 創(chuàng)建對象

2.1.1 工廠模式

工廠模式是一種較為簡單的設(shè)計(jì)模式,開發(fā)人員將創(chuàng)建對象的具體細(xì)節(jié)封裝在一個(gè)函數(shù)中。

// 工廠模式
function F(name, age) {
    let o = {};
    o.name = name;
    o.age = age;
    o.arr = ['a', 1, 2];
    return o
}

let p1 = F('Devin', 34)
p1.arr.push(5)
let p2 = F('Joker', 22)
p2.arr.push(10)
console.log(p1.name, p2.name) //Devin Joker
console.log(p1.age, p2.age)   //34 22
console.log(p1.arr, p2.arr)   //[ 'a', 1, 2, 5 ] [ 'a', 1, 2, 10 ]

工廠模式解決了創(chuàng)建多個(gè)類似對象的問題,但卻沒有解決對象識(shí)別的問題。

2.1.2 構(gòu)造器模式

諸如Object和Array等原生構(gòu)造器一樣,我們可以創(chuàng)建自定義構(gòu)造器去生成自定義對象。

// 構(gòu)造器模式
function F(name, age) {
    this.name = name;
    this.age = age;
    this.arr = ['a', 1, 2];
}

let p1 = new F('Devin', 34)
p1.arr.push(5)
let p2 = new F('Joker', 22)
p2.arr.push(10)
console.log(p1.name, p2.name) //Devin Joker
console.log(p1.age, p2.age)   //22 22
console.log(p1.arr, p2.arr)   //[ 'a', 1, 2, 5 ] [ 'a', 1, 2, 10 ]

與工廠模式相比,我們可以發(fā)現(xiàn)構(gòu)造器函數(shù)存在以下幾點(diǎn)不同:

  • 沒有顯式地創(chuàng)建對象
  • 直接將屬性和方法賦給了this對象
  • 沒有return語句

使用構(gòu)造器模式時(shí),需要注意必須使用new操作符。
構(gòu)造器模式雖然好用,但也存在問題,即它沒創(chuàng)建一個(gè)對象,所有的屬性都要重新創(chuàng)建一邊,某些情況下這種做法是并不可取的。

// 構(gòu)造器模式
function F(name) {
    this.name = name;
    this.sayName = function () {
        return this.name
    };
}

let p1 = new F('Devin')
let p2 = new F('Joker')
console.log(p1.sayName()) //Devin
console.log(p2.sayName()) //Joker
console.log(p1.sayName === p2.sayName) //false

上面的代碼中sayName函數(shù)只是單純的返回當(dāng)前對象中的名字,因此重復(fù)創(chuàng)建這個(gè)函數(shù)本身并沒有太大的意義,如果可以將sayName函數(shù)放入到一個(gè)共享的環(huán)境中就好了。我們一般會(huì)想到將sayName函數(shù)放入全局環(huán)境中,這種做法可行。

function sayName() {
    return this.name
}

function F(name) {
    this.name = name;
    this.sayName = sayName;
}

console.log(p1.sayName === p2.sayName) //false

這樣就很好的解決了浪費(fèi)內(nèi)存的問題,但是新的問題又來了,如果有很多個(gè)這樣的函數(shù),那就不得不在全局作用域中創(chuàng)建很多共享函數(shù),這么做會(huì)增加風(fēng)險(xiǎn),且構(gòu)造器本身也就沒有封裝性可言了。好在,這些問題我們可以用過原型模式去解決。

2.1.3 原型模式

我們創(chuàng)建的每個(gè)函數(shù)都有一個(gè)prototype屬性,這個(gè)屬性指向一個(gè)對象,這個(gè)對象包含所有實(shí)例共享的屬性和方法。

// 原型模式
function F() {}
F.prototype.name = 'Joker';
F.prototype.age = 22;

let p1 = new F()
let p2 = new F()
console.log(p1,p2)  //{ } { }
console.log(p1.name, p2.name)  //Joker Joker
p1.name = 'Devin';
p1.age = 34;
console.log(p1.name, p2.name) //Devin Joker
console.log(p1.age, p2.age)   //34 22

我們創(chuàng)建了兩個(gè)不同的實(shí)例,從打印結(jié)果中可以看出,他們本身是兩個(gè)空對象,但是訪問各自的name屬性,均可以打印出Joker,可見,在它們本身不具備該屬性時(shí),他們會(huì)到constructor的prototype中去找,當(dāng)為他們定義相同的屬性時(shí),實(shí)例本身的屬性會(huì)屏蔽原型上面的屬性。

原型模式也有不足之處,其根本來源是由于原型的共享性所致。

// 原型模式
function F() {}
F.prototype.arr = ['a', 1, 2];

let p1 = new F()
let p2 = new F()
p1.arr.push(5)
p2.arr.push(10)
console.log(p1.arr, p2.arr)  //[ 'a', 1, 2, 5, 10 ] [ 'a', 1, 2, 5, 10 ]
console.log(F.prototype.arr) //[ 'a', 1, 2, 5, 10 ]

對于prototype中的引用類型,實(shí)例中均采用指針的方式對其進(jìn)行訪問。任何實(shí)例對其修改都會(huì)影響到所有其他的實(shí)例對象。因此,在實(shí)際生產(chǎn)中,也很少單獨(dú)使用原型模式。

2.1.4 組合使用原型模式和構(gòu)造器模式

見題知意,就是將原型模式和構(gòu)造器模式組合在一起使用。

// 構(gòu)造器與原型組合模式
function F(name, age) {
    this.name = name;
    this.age = age;
    this.arr = [1, 2, 4]
}

F.prototype.sayName = function () {
    return this.name
}

let p1 = new F('Devin', 34)
p1.arr.push(5)
let p2 = new F('Joker', 22)
p2.arr.push(10)
console.log(p1) //{ name: 'Devin', age: 34, arr: [ 1, 2, 4, 5 ] }
console.log(p2) //{ name: 'Joker', age: 22, arr: [ 1, 2, 4, 10 ] }
console.log(p1.sayName()) //Devin
console.log(p2.sayName()) //Joker

在這個(gè)例子中,實(shí)例屬性都是在構(gòu)造函數(shù)中定義的,而共享屬性均在prototype屬性中??梢钥吹剑薷母髯缘腶rr并不會(huì)影響到其他實(shí)例對象。

2.1.5 其他方法

出上述幾種方法以外,還有動(dòng)態(tài)原型模式、寄生構(gòu)造函數(shù)模式、穩(wěn)妥構(gòu)造函數(shù)模式,這里不做介紹。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容