JavaScript對象理解

這幾天又好好讀了JavaScript高級程序設(shè)計限府。其中在理解對象和創(chuàng)建對象這塊有了很多新的見解和認(rèn)知

JavaScript的對象

由于我最開始學(xué)習(xí)的是Java秽荤,所以很容易就會把JavaScript和Java聯(lián)系到一起赂弓。不同于Java中橙依,ES5還是沒有類這個概念的喘漏。沒辦法通過類來實(shí)例化對象,更別說什么構(gòu)造函數(shù)繼承這些了椒功。

ECMA-262把對象定義:無序?qū)傩缘募希鋵傩钥梢园局抵鞘玻瑢ο蠡蛘吆瘮?shù)动漾。

簡單地創(chuàng)建對象

JavaScript創(chuàng)建對象很簡單,最基本的創(chuàng)建方法:

    var obj = new Object();  // 通過Object構(gòu)造函數(shù)來創(chuàng)建對象
    // 或者
    var obj2 = {//....balabala} // 通過對象字面量來創(chuàng)建對象

創(chuàng)建一個對象后,我們來了解一下對象的屬性類型:

對象的屬性類型

數(shù)據(jù)屬性:

數(shù)據(jù)屬性說的簡單點(diǎn)就是對象中具有具體數(shù)據(jù)值的屬性。如下中荠锭,name旱眯,age均為person的數(shù)據(jù)屬性。

    var person = {
      name: 'www',
      age: 18 
    }

每一個數(shù)據(jù)屬性呢证九,又包含四個屬性值删豺。顯示在對象中的是其value屬性±⒘可以由Object.defineProperty來定義它的這四個屬性呀页。
四個屬性:

1、configurable : 表示這個屬性是否是可配置的拥坛。默認(rèn)為true蓬蝶,如果修改為false,那么不可再修改這個屬性的configurable屬性和enumerable屬性猜惋,也不可用delete來刪除這個屬性丸氛。
2、enumerabel : 表示這個屬性是否是可枚舉的著摔。默認(rèn)為true缓窜。在比如Array這種引用類型中,它的那些例如sort()谍咆,push()等等的方法的這個屬性均為false禾锤,這樣我們就沒辦法用for in 來枚舉處其屬性愚臀。
3先慷、writable: 表示是否可修改惹恃。默認(rèn)為true。如果改為false港粱,那么就沒辦法再修改這個屬性值。
4旦签、value : 表示這個屬性的屬性值查坪。上面的name的value屬性就死 'www'。

Object.defineProperty方法的使用:

    Object.defineProperty(person,name,{
        // 這里我就取默認(rèn)情況
        configurable: true,
        enumerable: true,
        writable: true,
        value: 'www'
    })
訪問器屬性

訪問器屬性沒有具體的數(shù)據(jù)值宁炫,它提供一個getter和setter方法偿曙。
?這個就有點(diǎn)繞了。因?yàn)槲覀冊诙x對象的時候羔巢,像上面person這種望忆,它的name屬性我們是可以看得到的罩阵,很明顯就容易理解數(shù)據(jù)屬性。那么具體什么叫做訪問器屬性呢启摄?
?這里通過一個例子來說明一下稿壁。首先我們定義一個girl對象。女孩子的年齡都是保密的歉备,所以我們給它設(shè)置一個_age屬性傅是。那我們可以通過一個ask訪問器屬性來獲取到這個女孩的年齡。

    var girl = {
      _age:18, // 下劃線_開頭的屬性是一種約定俗成蕾羊,一般不作為公開屬性喧笔, 只能通過對象方法訪問。
      mood: "happy"      
    }
    // 定義一個ask訪問器屬性龟再。
    Object.defineProperty(girl,"ask",{
      // 我們可以通過girl.ask 來獲取到這個女孩18歲了书闸。
      get: function () {
         return this._age;
      } 
      // 要是我們給這個女孩設(shè)置一個 girl.ask = 20; 就像詢問這個女孩,你是不是20了吸申?女孩就會很生氣梗劫。    
         她的mood屬性就會變成 angry。
      set: function(val) {
        if(val > 18) {
          this.mood = "angry";
        }
      }
    })

這就是訪問器屬性截碴∈崆龋可以通過這個屬性獲取到其他屬性,也可以在設(shè)置這個屬性的時候日丹,導(dǎo)致別的屬性發(fā)生變化走哺。同時,這個屬性除了get和set兩個屬性哲虾,還有configurable和enumerable兩個屬性丙躏,類似于數(shù)據(jù)屬性。
關(guān)于讀取屬性和設(shè)置多個屬性等束凑,這些都是基本知識的介紹晒旅,可以閱讀《JavaScript高級程序設(shè)計》

高級程序設(shè)計

創(chuàng)建對象

上面說了很簡單通過Object構(gòu)造函數(shù)和對象字面量來創(chuàng)建對象。接下來說幾個逼格稍微高一點(diǎn)的汪诉。

工廠模式

JavaScript工廠模式創(chuàng)建對象就像是無限調(diào)用一個方法來創(chuàng)建Object對象废恋。這個方法就像是一個工廠一樣,如下代碼所示:

    function factory(name,age,sex) {
      var o = new Object();
      o.name = name;
      o.age = age;
      o.sex = sex;
      o.say = function () {
          console.log(o.name+'--'+o.age+'--'+o.sex);
      }
     return o;
  }
  // 創(chuàng)建實(shí)例對象
  var p1 = factory("wyh",18,"man");
  p1.say(); // wyh--18--man

缺點(diǎn):缺點(diǎn)太明顯了扒寄,我創(chuàng)造的對象全是Object的鱼鼓,沒有標(biāo)識度。實(shí)例化的p1,p2,p3也沒有任何的聯(lián)系该编。
所以迄本,讓我們來看構(gòu)造函數(shù)模式。

構(gòu)造函數(shù)模式

還是沒辦法摒棄Java的學(xué)習(xí)思想课竣。所以這里我很容易就聯(lián)想到Java的構(gòu)造函數(shù)嘉赎。JavaScript的構(gòu)造函數(shù)模式創(chuàng)建對象還真的很像Java的構(gòu)造函數(shù)置媳。如下代碼:

    // 與Java的構(gòu)造函數(shù)何其相似。函數(shù)內(nèi)部沒有顯示的創(chuàng)建對象的動作曹阔。 
    function Animal(name,leg) {
        this.name = name;
        this.leg = leg;
        this.sayName = function () {.....};
    }
    // 實(shí)例化兩個對象:通過new 來創(chuàng)建半开。
    var tiger = new Animal("tiger",4);
    var lion = new Animal("lion",4);
    console.log(tiger.constructor); // Function: Animal。   

好像很不錯赃份〖挪穑可是有嚴(yán)重的問題所在。每當(dāng)實(shí)例化一個Animal對象抓韩,就會給sayName開辟一個內(nèi)存空間纠永,如果這個對象有很多函數(shù)屬性,如果要實(shí)例化很多的Animal對象谒拴,就會很占用內(nèi)存空間了尝江。當(dāng)然,我們可以把這個對象的函數(shù)屬性放在全局變量中英上,但是同時也會污染了全局環(huán)境炭序。
所以,來看原型模式:

原型模式

由于我們創(chuàng)建的每個函數(shù)都是有一個叫做prototype(原型)的屬性苍日,該屬性作為一個指針指向一個對象惭聂。
所以我們可以利用這個prototype來進(jìn)行創(chuàng)建對象。這里僅僅介紹簡單的原型模式創(chuàng)建相恃,更具體的可以閱讀《JavaScript高級程序設(shè)計》辜纲。
代碼:

    function Person() {
    }
    Person.prototype.name = "wyh";
    Person.prototype.age = 18;
    Person.prototype.list = [],
    Person.prototype.sayName = function () {
        console.log(this.name);
    }
    var p1 = new Person();
    var p2 = new Person();
    p1.list.push("a");
    console.log(p2.list) // ['a']
    console.log(p1.constructor)  // Person
    console.log(p1.sayName == p2.sayName) // true;

解決了上面構(gòu)造函數(shù)模式中的函數(shù)占用內(nèi)存的問題了。因?yàn)樗袑?shí)例化的對象的函數(shù)指向的地址是一樣的拦耐。
缺點(diǎn):沒有辦法自定義初值耕腾,不具變通能力。
如上面所示杀糯,我在p1中操作了數(shù)組list扫俺,p2的也發(fā)生改變,這是不想看到的固翰。原型模式一個實(shí)例化對象更改引用類型狼纬,所有的都會改變。

組合使用構(gòu)造函數(shù)模式和原型模式

既然構(gòu)造函數(shù)和原型模式都各自有問題倦挂,而且還可以互補(bǔ)畸颅。那么我們就把這兩種模式結(jié)合到一起使用担巩。
代碼如下所示:

    function Person(name,age,sex) {
        this.name = name;
        this.age = age;
        this.sex = sex;
        this.shoplist = [];
    }
    Person.prototype = {
        sayName: function () {
            console.log(this.name);
        },
        constructor: Person
    }

    var p1 = new Person("wyh",18,"man");
    var p2 = new Person("MJ",16,"wm");
    p1.shoplist.push("apple");
    p2.shoplist.push("shoes");
    console.log(p1.sayName == p2.sayName); // true
    console.log(p1.constructor) // Person
    console.log(p2.shoplist) // ['shoes']

我們把公用的方法用原型模式構(gòu)造方援,省去內(nèi)存消耗。把不公用的引用類型用構(gòu)造函數(shù)模式構(gòu)造涛癌,避免混淆犯戏。
同時送火,也可以通過傳入初始化數(shù)據(jù)來自定義我們需要的對象的樣子。
這種方法(模式)是使用度最普遍的一種方法先匪。

動態(tài)原型模式

把上面那種模式中种吸,所有的信息都封裝在構(gòu)造函數(shù)中。但是又為了防止重復(fù)的初始化原型呀非,于是就有了動態(tài)原型模式坚俗。話不多說,請看代碼:

    function Person(name,age) {
        // 屬性
        this.name = name;
        this.age = age;
        // 動態(tài)地進(jìn)行原型的構(gòu)造方法
        if(typeof this.sayName != "function") {
            console.log('----1------');
            Person.prototype.sayName = function () {
                   console.log(this.name);
            }
            // 其他的需要原型處理的屬性
        }
    }

    var p1 = new Person("wyh",18); // 1
    p1.sayName(); // wyh
    var p2 = new Person("mj",16); // 什么都沒有
    p2.sayName(); // mj

當(dāng)我們第一次實(shí)例化Person的時候岸裙,會動態(tài)地創(chuàng)建原型屬性猖败,并且只創(chuàng)建這一次。

寄生構(gòu)造函數(shù)模式

這個降允。恩闻。。我看不太出來和工廠模式的區(qū)別剧董。要說實(shí)例化的時候用了new操作符的話幢尚,那我還是不明白這個模式的作用所在。

穩(wěn)妥構(gòu)造函數(shù)模式

同上面這個寄生構(gòu)造函數(shù)模式翅楼,我暫時看不出來它的用處所在尉剩。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市犁嗅,隨后出現(xiàn)的幾起案子边涕,更是在濱河造成了極大的恐慌,老刑警劉巖褂微,帶你破解...
    沈念sama閱讀 222,252評論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件功蜓,死亡現(xiàn)場離奇詭異,居然都是意外死亡宠蚂,警方通過查閱死者的電腦和手機(jī)式撼,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,886評論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來求厕,“玉大人著隆,你說我怎么就攤上這事⊙窖ⅲ” “怎么了美浦?”我有些...
    開封第一講書人閱讀 168,814評論 0 361
  • 文/不壞的土叔 我叫張陵,是天一觀的道長项栏。 經(jīng)常有香客問我浦辨,道長,這世上最難降的妖魔是什么沼沈? 我笑而不...
    開封第一講書人閱讀 59,869評論 1 299
  • 正文 為了忘掉前任流酬,我火速辦了婚禮币厕,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘芽腾。我一直安慰自己旦装,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,888評論 6 398
  • 文/花漫 我一把揭開白布摊滔。 她就那樣靜靜地躺著阴绢,像睡著了一般。 火紅的嫁衣襯著肌膚如雪艰躺。 梳的紋絲不亂的頭發(fā)上旱函,一...
    開封第一講書人閱讀 52,475評論 1 312
  • 那天,我揣著相機(jī)與錄音描滔,去河邊找鬼棒妨。 笑死,一個胖子當(dāng)著我的面吹牛含长,可吹牛的內(nèi)容都是我干的券腔。 我是一名探鬼主播,決...
    沈念sama閱讀 41,010評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼拘泞,長吁一口氣:“原來是場噩夢啊……” “哼纷纫!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起陪腌,我...
    開封第一講書人閱讀 39,924評論 0 277
  • 序言:老撾萬榮一對情侶失蹤辱魁,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后诗鸭,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體染簇,經(jīng)...
    沈念sama閱讀 46,469評論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,552評論 3 342
  • 正文 我和宋清朗相戀三年强岸,在試婚紗的時候發(fā)現(xiàn)自己被綠了锻弓。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,680評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡蝌箍,死狀恐怖青灼,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情妓盲,我是刑警寧澤杂拨,帶...
    沈念sama閱讀 36,362評論 5 351
  • 正文 年R本政府宣布,位于F島的核電站悯衬,受9級特大地震影響弹沽,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,037評論 3 335
  • 文/蒙蒙 一贷币、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧亏狰,春花似錦役纹、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,519評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至策州,卻和暖如春瘸味,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背够挂。 一陣腳步聲響...
    開封第一講書人閱讀 33,621評論 1 274
  • 我被黑心中介騙來泰國打工旁仿, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人孽糖。 一個月前我還...
    沈念sama閱讀 49,099評論 3 378
  • 正文 我出身青樓枯冈,卻偏偏與公主長得像,于是被迫代替她去往敵國和親办悟。 傳聞我的和親對象是個殘疾皇子尘奏,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,691評論 2 361

推薦閱讀更多精彩內(nèi)容