JavaScript: 創(chuàng)建對象的多種模式

  • 工廠模式
function createPerson(name, age, job){
 var o = new Object();
 o.name = name;
 o.age = age
 o.job = job;
 o.sayName = function(){
  alert(this.name);
 }
 return o;
}

var person1 = createPerson('a', 18, 'coder');
var person2 = createPerson('a', 18, 'coder');

工作模式是通過一個函數(shù)返回一個對象钢坦,但是有個問題是:新建對象實例和普通的調用函數(shù)沒有辨識度。

  • 構造函數(shù)模式
function Person(){
 this.name = name;
 this.age = age;
 this.job = job;
 this.sayName = function(){
  alert(this.name); 
 }
}

var person1 = new Person('a', 18, 'coder');
var person2 = new Person('b', 18, 'coder');
  • 和工廠模式相比咕村,構造函數(shù)模式场钉,沒有顯示地創(chuàng)建對象,并返回懈涛,而是直接將屬性和“靜態(tài)“方法賦值給this對象逛万。使用new操作符新建實例,this對象引用的是以Person對象為模板的新對象批钠。
  • 使用new操作符這種方式調用構造函數(shù)宇植,實際上是經歷了下面四個步驟:
  1. 創(chuàng)建一個新對象;
  2. 將構造函數(shù)的作用域賦值給新對象(因此this對象引用的是新對象埋心,而不是原型對象)指郁;
  3. 執(zhí)行構造函數(shù)的代碼;
  4. 返回這個新對象拷呆。

上面的工廠模式也是經歷的這幾個步驟闲坎,不過工廠模式是在構造函數(shù)中使用new操作符新建對象實例疫粥。

?

使用構造函數(shù)模式,解決了“標識函數(shù)和類型”的問題腰懂,但是如果在構造函數(shù)內部新建函數(shù)就會有個問題:
在實例person1和person2中都sayName函數(shù)梗逮,雖然功能相同,
但是他們卻是開辟了兩個空間绣溜,新建了兩個函數(shù)慷彤,因為他們各自在不同的作用域中。

避免重復新建同樣功能函數(shù)怖喻,避免冗余可以這樣做:

function Person(name, age, job){
  this.name = name;
  this.age = age;
  this.job = job;
  this.sayName = sayName;
}
function sayName(){
  alert(this.name);
}

這樣做也帶來一個新的問題:
為了避免同功能函數(shù)的冗余底哗,然后我們把這些”靜態(tài)函數(shù)”都放在了全局作用域中,而在新對象中進行引用锚沸。但是一旦函數(shù)多起來跋选,封裝性就會失去,一堆函數(shù)在全局作用域咒吐,這樣也污染全局作用域野建。我自己的一個折中的做法是:用“+function(){ /*代碼/ }()”包裹属划。js提供另外一種方法:原型模式*

  • 原型模式

構造函數(shù)會有一個prototype屬性恬叹,他存放的是一個指針,指向原型對象同眯,實例也是有個功能相同的內部屬性[[prototype]] / __proto__(__proto__屬性只在FireFox绽昼、chrome、Safari得到支持)指向原型對象须蜗,而原型對象中則有一個屬性硅确,constructor,他指向構造函數(shù)明肮,而prototype是原型模式的核心:

  • prototype / [[prototype]]菱农,該屬性存放的是一個指針,指向原型對象柿估;
  • 原型對象的屬性:constructor循未,該屬性存放的是一個指針,指向構造函數(shù)秫舌;
+function(){
    function Person(){}
    Person.prototype.name = 'issac';
    Person.prototype.age = 18;
    Person.prototype.sayName = function(){
        console.log(this.name);
    }
}();
var person1 = new Person('a', 18);

更簡單的原型語法

將對象賦值給prototype屬性的妖,即使用字面量的方法簡寫為:

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

這樣雖然可以很好的簡寫,但要注意的一點是足陨,這樣做相當于重寫了原型對象嫂粟,constructor不再指向Person,而是指向Object構造函數(shù)墨缘。如果要使用到這個屬性星虹,就要手動將constructor指向Person

Person.prototype = {
    constructor: Person,
    sayName: function(){ console.log(this.name) }
};

這樣做零抬,也并非和默認獲得的constructor屬性相同,因為該屬性是手動添加的宽涌,那么內部屬性[[Enumerable]]是默認為true的媚值,而默認獲得的constructor的枚舉是false的』ぬ牵可以使用defineProperty方法設置

Object.defineProperty(Person.proptotype, 'constructor', {
  enumerable: fase,
  value: Person
});
  • 只用原型模式的問題

原型模式最大的問題是由他的共享性引起褥芒,在屬性還是基本類型的時候還沒有什么問題,但如果是引用類型嫡良,問題就很明顯了锰扶。

function Person(){}
Person.prototype.name = 'issac';
Person.prototype.arr = ['issac', 'is', 'iron'];
var p1 = new Person();
var p2 = new Person();
p1.arr.push('man');
console.log(p1.arr);  //['issac', 'is', 'iron', 'man']
console.log(p2.arr);  //['issac', 'is', 'iron', 'man']

如果一開始就是打算共享這個數(shù)組還好說,但是更多時候這種情況是希望每個對象實例擁有獨立的數(shù)組寝受。這也是坷牛,比較少單獨使用原型模式的原因。

?

  • 小插曲:實例對象中建立和原型對象屬性同名的屬性很澄,會屏蔽原型對象的屬性京闰,就算將實例對象中的同名屬性賦值為null也不能取消屏蔽,但是可以使用 delete 操作符 刪除實例對象中的同名屬性甩苛,可以重新訪問到原型對象中的同名屬性蹂楣。
    ?
  • hasOwnProperty可以用來判斷屬性是不是屬于實例對象
  • 組合原型模式和構造函數(shù)模式

從上面的構造函數(shù)模式和原型模式,可以知道讯蒲,構造函數(shù)模式痊土,定義的屬性和方法是非共享的,在新建對象實例時復制了一份屬性副本(沒有必要在這里定義方法墨林,因為方法功能一樣赁酝,不必給每個實例分配一個副本,這是冗余旭等,浪費內存)酌呆,都是獨立的;而用原型模式構造的屬性和方法是共享的搔耕,每個屬性調用的原型屬性和方法都是共享的隙袁,相當于靜態(tài)的屬性/方法。
結合這兩個特點度迂,可以以構造函數(shù)模式定義實例屬性/方法(非共享)藤乙,以原型模式定義靜態(tài)方法/屬性(共享)

//構造實例屬性
function Person(name, age, job){
  this.name = name;
  this.age = age;
  this.job = job;
  this.not_share = ['issac', 'frank'];
}
//靜態(tài)的共享屬性/方法
Person.prototype = {
  sayName: function(){
    console.log(this.name);
  },
  share: ['issac', 'person'],
};
var p1 = new Person('a', 18, 'coder');
var p2 = new Person('b', 18, 'coder');
p1.share.push('dube');
p1.not_share.push('dube');
console.log(p1.share);
console.log(p2.share);
console.log(p1.not_share);
console.log(p2.not_share);
Paste_Image.png
  • 寄生構造函數(shù)模式

個人是認為這種模式適合用在原生對象上進行擴展,這樣也很適合“寄生”這一詞惭墓。

//給Array添加一個特殊的方法坛梁,但是有不污染Array對象
function SpecialArray(){
  var values = new Array();
  values.push.apply(values, arguments);
  values.toPipedString = function(){
    return this.join("|");
  };
  return values;
}
var arr = new SpecialArray('red', 'white', 'new');
console.log(arr.toPipedString());

一個小插曲,也是寫到這里才知道腊凶,函數(shù)可以不寫形參划咐,而直接從arguments對象(數(shù)組)中獲取實參拴念。


Paste_Image.png
  • 小結:主要介紹了以下五種創(chuàng)建對象的模式。
  1. 工廠模式;
  1. 構造函數(shù)模式褐缠;
  2. 原型模式政鼠;
  3. 組合原型模式和構造函數(shù)模式;
  4. 寄生構造函數(shù)模式队魏;
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末公般,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子胡桨,更是在濱河造成了極大的恐慌官帘,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,723評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件昧谊,死亡現(xiàn)場離奇詭異刽虹,居然都是意外死亡,警方通過查閱死者的電腦和手機呢诬,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,485評論 2 382
  • 文/潘曉璐 我一進店門涌哲,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人尚镰,你說我怎么就攤上這事阀圾。” “怎么了钓猬?”我有些...
    開封第一講書人閱讀 152,998評論 0 344
  • 文/不壞的土叔 我叫張陵稍刀,是天一觀的道長。 經常有香客問我敞曹,道長,這世上最難降的妖魔是什么综膀? 我笑而不...
    開封第一講書人閱讀 55,323評論 1 279
  • 正文 為了忘掉前任澳迫,我火速辦了婚禮,結果婚禮上剧劝,老公的妹妹穿的比我還像新娘橄登。我一直安慰自己,他們只是感情好讥此,可當我...
    茶點故事閱讀 64,355評論 5 374
  • 文/花漫 我一把揭開白布拢锹。 她就那樣靜靜地躺著,像睡著了一般萄喳。 火紅的嫁衣襯著肌膚如雪卒稳。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,079評論 1 285
  • 那天他巨,我揣著相機與錄音充坑,去河邊找鬼减江。 笑死,一個胖子當著我的面吹牛捻爷,可吹牛的內容都是我干的辈灼。 我是一名探鬼主播,決...
    沈念sama閱讀 38,389評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼也榄,長吁一口氣:“原來是場噩夢啊……” “哼巡莹!你這毒婦竟也來了?” 一聲冷哼從身側響起甜紫,我...
    開封第一講書人閱讀 37,019評論 0 259
  • 序言:老撾萬榮一對情侶失蹤榕莺,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后棵介,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體钉鸯,經...
    沈念sama閱讀 43,519評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 35,971評論 2 325
  • 正文 我和宋清朗相戀三年邮辽,在試婚紗的時候發(fā)現(xiàn)自己被綠了唠雕。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,100評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡吨述,死狀恐怖岩睁,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情揣云,我是刑警寧澤捕儒,帶...
    沈念sama閱讀 33,738評論 4 324
  • 正文 年R本政府宣布,位于F島的核電站邓夕,受9級特大地震影響刘莹,放射性物質發(fā)生泄漏。R本人自食惡果不足惜焚刚,卻給世界環(huán)境...
    茶點故事閱讀 39,293評論 3 307
  • 文/蒙蒙 一点弯、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧矿咕,春花似錦抢肛、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,289評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至莲镣,卻和暖如春福稳,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背剥悟。 一陣腳步聲響...
    開封第一講書人閱讀 31,517評論 1 262
  • 我被黑心中介騙來泰國打工灵寺, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留曼库,地道東北人。 一個月前我還...
    沈念sama閱讀 45,547評論 2 354
  • 正文 我出身青樓略板,卻偏偏與公主長得像毁枯,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子叮称,可洞房花燭夜當晚...
    茶點故事閱讀 42,834評論 2 345

推薦閱讀更多精彩內容