JavaScript之對象

在ES6出現之前,JavaScript不能真正被稱為 面向對象的編程語言壤躲,因為 class 僅僅作為其保留字而非關鍵字,而ES6之后备燃,引入了class碉克,使程序員可以用自己更加熟悉的方式創(chuàng)建對象;

至于ES6和ES5有什么區(qū)別并齐,應該就是上面提到的可以讓程序員更爽地coding漏麦,而程序員爽了客税,根據 工作量守恒定律,總有某個事物要干更多的活撕贞,沒錯更耻,就是計算機。

為了兼容某些不支持ES6的瀏覽器捏膨,我們可以引入 Babel 庫將ES6代碼 “編譯” 成ES5之后執(zhí)行,而對于支持ES6的瀏覽器秧均,在其JavaScript引擎中會自動進行“編譯”操作;

所以号涯,總體上看目胡,ES6和ES5在功能上是等效的,即用ES6能完成的任務链快,用ES5必然能夠完成誉己,只是在語法上,ES6提供了更多的 語法糖域蜗,讓程序員嘗到甜頭巨双;所以為了更好的理解JavaScript對象,我們回歸初心地消,從ES5中窺視JavaScript所創(chuàng)建的對象世界炉峰;

對象的創(chuàng)建

對象有兩個基本元素:屬性和方法;

屬性用于存儲數據脉执,方法用于存儲代碼疼阔;接下來,我們從簡單到復雜半夷,來理解JavaScript創(chuàng)建對象的演變史婆廊。

創(chuàng)建Object對象并賦值時代

我們可以通過 new Object 創(chuàng)建Object,并為其賦屬性和方法來創(chuàng)建對象:

// 代碼段 1
var p = new Object();
p.name = "x";
p.age = 20;
p.say = function(){
  console.log("My name is",this.name,",this year is",this.age);
}

這樣我們就得到一個含有2個屬性巫橄,1個方法的對象淘邻;

通過執(zhí)行 p.say() 得到輸出 : My name is x ,this year is 20 ;

但是,這些幾行代碼非常松散湘换,每一行代碼都像一條單獨的語句宾舅,為了體現這些屬性和方法是一個整體,而不是一個個獨立的存在彩倚,我們需要進入下一個時代筹我;

字面量賦值時代

我們通過給一個變量賦一個字面量,即可創(chuàng)建一個對象:

// 代碼段 2
var p = {
  name : "x" ,
  age : 20 , 
  say : function(){
    console.log("My name is",this.name,",this year is",this.age);
  }
}

這樣帆离,我們就創(chuàng)建好了一個對象蔬蕊,這個對象有了自己的屬性和方法;

通過 console.log(typeof p) ,輸出為object可知哥谷, p 的類型是一個對象岸夯;

代碼段1和代碼段2相比麻献,代碼段2的結構更為合理,所有的屬性和方法都用大括號包含猜扮,更利于閱讀勉吻,也體現了整體性,但功能上是等效的破镰;

不過我們又發(fā)現餐曼,每次要創(chuàng)建一個相似的對象,都需要寫一遍屬性名鲜漩,非常地不優(yōu)雅源譬,所以,我們又要進入下一個時代孕似;

工廠模式時代

我們可以通過調用一個函數創(chuàng)建我們需要的對象踩娘,并返回該對象,從而使代碼可重用喉祭,這個函數就是傳說中的 工廠养渴,代碼如下:

// 代碼 3
function createPerson(name,age){
  var t = new Object();
  t.name = name;
  t.age = age;
  t.say = function(){
    console.log("My name is",this.name,",this year is",this.age);
  }
  return t;
}
var p = createPerson("x",20);

代碼3是將代碼1變?yōu)榱斯S模式;

下面再將代碼2也變?yōu)楣S模式:

function createPerson(name,age){
  return {
    name:name,
    age : age,
    say = function(){
      console.log("My name is",this.name,",this year is",this.age);
    }
  };
}
var p = createPerson("x",20);
```
工廠模式的代碼要比前面兩個時代的代碼優(yōu)雅泛烙,我們只需要調用一個函數即可獲得我們想要的對象理卑;

但是,我們又發(fā)現了一個新的問題(別問我為什么總是能發(fā)現新問題蔽氨,因為就是有一雙善于觀察的眼睛藐唠,手動傲嬌 ^_^):

通過上述3中方式創(chuàng)建的對象在使用 `typeof` 時,返回的都是 `object`鹉究,而通過 `實例 instanceof 類` 只有在類為 `Object`時宇立,才返回true,就是說自赔,上面3中方法創(chuàng)建的對象都是無差別的對象妈嘹,我們不能分辨出它們的類型;

這就麻煩了绍妨,比如我們有這么一個函數:
```javascript
function seeDoctor( o ){
  if(o是人){
    請人醫(yī)治療
  }
  if(o是動物){
    請獸醫(yī)治療
  }
}
```
那我們創(chuàng)建的對象因為不能判斷其是人是獸润脸,將不能選擇適合的治療方案;

要解決這個問題他去,有兩種思路:
- 給對象添加信息津函,即為每一個對象添加一個屬性 `type` ,用于指明其類型孤页;
- 讓js解釋器能夠判斷其類型;

第一種方式比較 *丑陋*涩馆,我們需要管理更多的數據行施,但比較容易理解允坚;第二種是更優(yōu)雅的方法,也推動我們進入下一個時代蛾号;

### 構造函數時代

構造函數時代的主要任務是讓創(chuàng)建的對象自帶類別說明屬性稠项,即通過`instanceof` 就能判斷出其所屬的類:
```javascript
// 類是一個函數,約定:
// 普通函數第一個字母小寫鲜结,類函數第一個字母大寫
function Person(name,age){
  this.name = name;
  this.age = age;
  this.say = function(){
    console.log("My name is",this.name,",this year is",this.age);
  }
}
function Animal(){}
var p = new Person("x",20) ;
```
注意展运,創(chuàng)建對象時,必須使用關鍵字 **new** 精刷。

此時拗胜,我們通過 `p instanceof Person`,返回的結果為 `true`怒允,而通過 `p instanceof Animal` 埂软,返回結果為 `false`,從而使對象實例自帶類型屬性纫事;

完美勘畔! But,又雙叒叕發(fā)現了不足丽惶,我們用上述各種函數創(chuàng)建兩個對象:
```javascript
var p1 = new Person("x",20);
var p2 = new Person("y",21);
console.log(p1.say==p2.say) ; // 輸出的是false
```
我們發(fā)現:雖然 *say* 函數的代碼相同炫七,但兩個對象實例的 *say* 居然指向不同的代碼塊,如果我們有100個實例钾唬,相同的代碼塊就需要有100份万哪,極大的內存浪費,這是我們所不能忍受的知纷,因此迫切希望下一個時代的到來壤圃!

### 構造函數+原型時代

原型就是所有對象實例所共享的一個 **對象**,這個對象中的屬性就是共享屬性(在c++中稱為靜態(tài)變量)琅轧,方法就是共享方法伍绳; 

```javascript
function Person(name,age){
  this.name = name;
  this.age = age;
}
Person.prototype.say = function(){
  console.log("My name is",this.name,",this year is",this.age);
}
var p = new Person("x",20);
```
上述代碼創(chuàng)建的對象實例 p 有自己的屬性name和age,以及共享的方法say乍桂;通過 `p.say()` 即可打印出:*My name is x ,this year is 20* ;

執(zhí)行 `p.say()` 的時候冲杀,p先搜索其自身是否有方法 `say`,如果有睹酌,就執(zhí)行权谁,如果沒有,就搜索其原型對象是否有 `say` 方法憋沿,如果還是沒有旺芽,就搜索其原型對象的原型對象是否有say屬性(即沿著原型鏈搜索say方法,這也是繼承的實現機制),如果原型鏈上都沒有say方法采章,就拋出錯誤运嗜,否則,執(zhí)行搜索到的方法悯舟。

p通過屬性`p.__proto__` 指向原型對象 `Person.prototype` , 從而獲取原型上的所有屬性和方法担租;

如果p上也定義一個方法 `say`:
```javascript
p.say = function(){console.log("Hello,world");}
```
則該方法將會 **覆蓋** 原型上的say方法,即調用 `p.say` 輸出的將是 *Hello,world* 抵怎,而如果通過 `delete p.say` 刪除掉 `say` 屬性奋救,則調用 `p.say` 時,執(zhí)行的代碼又是原型上的 say 代碼反惕;

總結:原型就是一個類所創(chuàng)建的所有對象實例共享的一個對象尝艘;

但是,原型對象的定義和構造函數分開了承璃,這又使結構不太優(yōu)美利耍,所以,我們又得進入下一個時代盔粹;

### 構造原型時代

為了解決原型定義和構造函數分離的問題隘梨,我們決定將原型定義放到構造函數中,就出現了以下代碼:

```javascript
function Person(name,age){
  this.name = name;
  this.age = age;
  Person.prototype.say = function(){
    console.log("My name is",this.name,",this year is",this.age);
  }
}
var p = new Person("x",20);
```
OK舷嗡,完成了原型定義和構造函數的合并轴猎,結構也變得更加優(yōu)美了,但是进萄,又出現了一個問題:

每次執(zhí)行創(chuàng)建 Person 對象實例的時候捻脖,都要重新定義一遍 `Person.prototype.say` 方法,雖然這不會增加內存泄漏(以前定義的say代碼由于沒有被引用中鼠,內存塊將會被自動回收)可婶,但卻增加了cpu的工作量,所以我們需要進入下一個時代援雇;

### 優(yōu)化構造原型時代

為了避免 `Person.prototype.say` 函數的重復定義矛渴,我們可以先判斷該函數是否已定義,如果沒有定義惫搏,再對其進行定義:

```javascript
function Person(name,age){
  this.name = name;
  this.age = age;
  if(typeof(Person.prototype.say)=="undefined"){
    Person.prototype.say = function(){
      console.log("My name is",this.name,",this year is",this.age);
    } ;
  }
}
var p = new Person("x",20);
```
通過以上7個時代的迭代具温,我們終于在 JavaScript中創(chuàng)建了一個基本上符合我們要求的對象; 

完筐赔!

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末铣猩,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子茴丰,更是在濱河造成了極大的恐慌达皿,老刑警劉巖天吓,帶你破解...
    沈念sama閱讀 216,651評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現場離奇詭異鳞绕,居然都是意外死亡失仁,警方通過查閱死者的電腦和手機,發(fā)現死者居然都...
    沈念sama閱讀 92,468評論 3 392
  • 文/潘曉璐 我一進店門们何,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人控轿,你說我怎么就攤上這事冤竹。” “怎么了茬射?”我有些...
    開封第一講書人閱讀 162,931評論 0 353
  • 文/不壞的土叔 我叫張陵鹦蠕,是天一觀的道長。 經常有香客問我在抛,道長钟病,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,218評論 1 292
  • 正文 為了忘掉前任刚梭,我火速辦了婚禮肠阱,結果婚禮上,老公的妹妹穿的比我還像新娘朴读。我一直安慰自己屹徘,他們只是感情好,可當我...
    茶點故事閱讀 67,234評論 6 388
  • 文/花漫 我一把揭開白布衅金。 她就那樣靜靜地躺著噪伊,像睡著了一般。 火紅的嫁衣襯著肌膚如雪氮唯。 梳的紋絲不亂的頭發(fā)上鉴吹,一...
    開封第一講書人閱讀 51,198評論 1 299
  • 那天,我揣著相機與錄音惩琉,去河邊找鬼豆励。 笑死,一個胖子當著我的面吹牛琳水,可吹牛的內容都是我干的肆糕。 我是一名探鬼主播,決...
    沈念sama閱讀 40,084評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼在孝,長吁一口氣:“原來是場噩夢啊……” “哼诚啃!你這毒婦竟也來了?” 一聲冷哼從身側響起私沮,我...
    開封第一講書人閱讀 38,926評論 0 274
  • 序言:老撾萬榮一對情侶失蹤始赎,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發(fā)現了一具尸體造垛,經...
    沈念sama閱讀 45,341評論 1 311
  • 正文 獨居荒郊野嶺守林人離奇死亡魔招,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,563評論 2 333
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現自己被綠了五辽。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片办斑。...
    茶點故事閱讀 39,731評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖杆逗,靈堂內的尸體忽然破棺而出乡翅,到底是詐尸還是另有隱情,我是刑警寧澤罪郊,帶...
    沈念sama閱讀 35,430評論 5 343
  • 正文 年R本政府宣布蠕蚜,位于F島的核電站,受9級特大地震影響悔橄,放射性物質發(fā)生泄漏靶累。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,036評論 3 326
  • 文/蒙蒙 一癣疟、第九天 我趴在偏房一處隱蔽的房頂上張望挣柬。 院中可真熱鬧,春花似錦争舞、人聲如沸凛忿。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,676評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽店溢。三九已至,卻和暖如春委乌,著一層夾襖步出監(jiān)牢的瞬間床牧,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,829評論 1 269
  • 我被黑心中介騙來泰國打工遭贸, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留戈咳,地道東北人。 一個月前我還...
    沈念sama閱讀 47,743評論 2 368
  • 正文 我出身青樓壕吹,卻偏偏與公主長得像著蛙,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子耳贬,可洞房花燭夜當晚...
    茶點故事閱讀 44,629評論 2 354

推薦閱讀更多精彩內容

  • 前言 這是讀書筆記第二篇踏堡,看完之后突然發(fā)現自己對js的內置的一些東西還是了解的不夠全面,很多方法見都沒見過咒劲,啥用都...
    不止前端閱讀 188評論 0 0
  • 中午藤违,有個同事問我們需不需要買鞋翩腐,她說她領取了一家鞋店的優(yōu)惠券御雕,有很多張,都是滿100減100的削樊,優(yōu)惠力度特別的大...
    辰苓閱讀 1,120評論 0 2
  • copy和mutablecopy 源于對數據的復制需求豁生,對于對象類型的數據來說,區(qū)別于直接持有這個數據對象的方式漫贞,...
    縱橫而樂閱讀 400評論 0 1
  • 職位描述 【崗位職責】 1沛硅、對房地產市場數據進行日常收集歸類統(tǒng)計;及時跟蹤和研究國家宏觀經濟政策的走向绕辖,對國家重大...
    沒頭沒腦傻開心閱讀 476評論 0 2
  • 小洋洋出生后,我與寶爸基本沒有二人世界啦擂红,有的都是三人世界仪际。但這個周末的三人世界有點特別(∩_∩)。 上篇更文中寶...
    李梅樹閱讀 628評論 1 3