構(gòu)造函數(shù)內(nèi)的方法與構(gòu)造函數(shù)`prototype`屬性上方法的對(duì)比

本文的目的是讓大家理解什么情況下把函數(shù)的方法寫在JavaScript的構(gòu)造函數(shù)上,什么時(shí)候把方法寫在函數(shù)的prototype屬性上;以及這樣做的好處.

為了閱讀方便,我們約定一下:把方法寫在構(gòu)造函數(shù)內(nèi)的情況我們簡(jiǎn)稱為函數(shù)內(nèi)方法,把方法寫在prototype屬性上的情況我們簡(jiǎn)稱為prototype上的方法

首先我們先了解一下這篇文章的重點(diǎn):

  • 函數(shù)內(nèi)的方法: 使用函數(shù)內(nèi)的方法我們可以訪問到函數(shù)內(nèi)部的私有變量,如果我們通過構(gòu)造函數(shù)new出來的對(duì)象需要我們操作構(gòu)造函數(shù)內(nèi)部的私有變量的話,
    我們這個(gè)時(shí)候就要考慮使用函數(shù)內(nèi)的方法.
  • prototype上的方法: 當(dāng)我們需要通過一個(gè)函數(shù)創(chuàng)建大量的對(duì)象,并且這些對(duì)象還都有許多的方法的時(shí)候;這時(shí)我們就要考慮在函數(shù)的prototype上添加這些方法.
    這種情況下我們代碼的內(nèi)存占用就比較小.
  • 在實(shí)際的應(yīng)用中,這兩種方法往往是結(jié)合使用的;所以我們要首先了解我們需要的是什么,然后再去選擇如何使用.

我們還是根據(jù)下面的代碼來說明一下這些要點(diǎn)吧,下面是代碼部分:

// 構(gòu)造函數(shù)A
function A(name) {
    this.name = name || 'a';
    this.sayHello = function() {
        console.log('Hello, my name is: ' + this.name);
    }
}

// 構(gòu)造函數(shù)B
function B(name) {
    this.name = name || 'b';
}
B.prototype.sayHello = function() {
    console.log('Hello, my name is: ' + this.name);
};

var a1 = new A('a1');
var a2 = new A('a2');
a1.sayHello();
a2.sayHello();

var b1 = new B('b1');
var b2 = new B('b2');
b1.sayHello();
b2.sayHello();

我們首先寫了兩個(gè)構(gòu)造函數(shù),第一個(gè)是A,這個(gè)構(gòu)造函數(shù)里面包含了一個(gè)方法sayHello;第二個(gè)是構(gòu)造函數(shù)B,
我們把那個(gè)方法sayHello寫在了構(gòu)造函數(shù)Bprototype屬性上面.

需要指出的是,通過這兩個(gè)構(gòu)造函數(shù)new出來的對(duì)象具有一樣的屬性和方法,但是它們的區(qū)別我們可以通過下面的一個(gè)圖來說明:

1

我們通過使用構(gòu)造函數(shù)A創(chuàng)建了兩個(gè)對(duì)象,分別是a1,a2;通過構(gòu)造函數(shù)B創(chuàng)建了兩個(gè)對(duì)象b1,b2;我們可以發(fā)現(xiàn)b1,b2這兩個(gè)對(duì)象的那個(gè)sayHello方法
都是指向了它們的構(gòu)造函數(shù)的prototype屬性的sayHello方法.而a1,a2都是在自己內(nèi)部定義了這個(gè)方法.
定義在構(gòu)造函數(shù)內(nèi)部的方法,會(huì)在它的每一個(gè)實(shí)例上都克隆這個(gè)方法;定義在構(gòu)造函數(shù)的prototype屬性上的方法會(huì)讓它的所有示例都共享這個(gè)方法,但是不會(huì)在每個(gè)實(shí)例的內(nèi)部重新定義這個(gè)方法.
如果我們的應(yīng)用需要?jiǎng)?chuàng)建很多新的對(duì)象,并且這些對(duì)象還有許多的方法,為了節(jié)省內(nèi)存,我們建議把這些方法都定義在構(gòu)造函數(shù)的prototype屬性上

當(dāng)然,在某些情況下,我們需要將某些方法定義在構(gòu)造函數(shù)中,這種情況一般是因?yàn)槲覀冃枰?strong>訪問構(gòu)造函數(shù)內(nèi)部的私有變量.

下面我們舉一個(gè)兩者結(jié)合的例子,代碼如下:

function Person(name, family) {
    this.name = name;
    this.family = family;
    
    var records = [{type: "in", amount: 0}];

    this.addTransaction = function(trans) {
        if(trans.hasOwnProperty("type") && trans.hasOwnProperty("amount")) {
           records.push(trans);
        }
    }

    this.balance = function() {
       var total = 0;

       records.forEach(function(record) {
           if(record.type === "in") {
             total += record.amount;
           }
           else {
             total -= record.amount;
           }
       });
    
        return total;
    };
};

Person.prototype.getFull = function() {
    return this.name + " " + this.family;
};

Person.prototype.getProfile = function() {
     return this.getFull() + ", total balance: " + this.balance();
};

在上面的代碼中,我們定義了一個(gè)Person構(gòu)造函數(shù);這個(gè)函數(shù)有一個(gè)內(nèi)部的私有變量records,這個(gè)變量我們是不希望通過函數(shù)內(nèi)部以外的方法
去操作這個(gè)變量,所以我們把操作這個(gè)變量的方法都寫在了函數(shù)的內(nèi)部.而把一些可以公開的方法寫在了Personprototype屬性上,比如方法getFullgetProfile.

把方法寫在構(gòu)造函數(shù)的內(nèi)部,增加了通過構(gòu)造函數(shù)初始化一個(gè)對(duì)象的成本,把方法寫在prototype屬性上就有效的減少了這種成本.
你也許會(huì)覺得,調(diào)用對(duì)象上的方法要比調(diào)用它的原型鏈上的方法快得多,其實(shí)并不是這樣的,如果你的那個(gè)對(duì)象上面不是有很多的原型的話,它們的速度其實(shí)是差不多的

另外,需要注意的一些地方:

  • 首先如果是在函數(shù)的prototype屬性上定義方法的話,要牢記一點(diǎn),如果你改變某個(gè)方法,那么由這個(gè)構(gòu)造函數(shù)產(chǎn)生的所有對(duì)象的那個(gè)方法都會(huì)被改變.
  • 還有一點(diǎn)就是變量提升的問題,我們可以稍微的看一下下面的代碼:
    func1(); // 這里會(huì)報(bào)錯(cuò),因?yàn)樵诤瘮?shù)執(zhí)行的時(shí)候,func1還沒有被賦值. error: func1 is not a function
    var func1 = function() {
        console.log('func1');
    };
    
    func2(); // 這個(gè)會(huì)被正確執(zhí)行,因?yàn)楹瘮?shù)的聲明會(huì)被提升.
    function func2() {
        console.log('func2');
    }
    
  • 關(guān)于對(duì)象序列化的問題.定義在函數(shù)的prototype上的屬性不會(huì)被序列化,可以看下面的代碼:
    function A(name) {
        this.name = name;
    }
    A.prototype.sayWhat = 'say what...';
    
    var a = new A('dreamapple');
    console.log(JSON.stringify(a));
    
    我們可以看到輸出結(jié)果是{"name":"dreamapple"}

參考的文章或者問答:

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市追城,隨后出現(xiàn)的幾起案子胶坠,更是在濱河造成了極大的恐慌,老刑警劉巖酝惧,帶你破解...
    沈念sama閱讀 218,204評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異伯诬,居然都是意外死亡晚唇,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,091評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門盗似,熙熙樓的掌柜王于貴愁眉苦臉地迎上來哩陕,“玉大人,你說我怎么就攤上這事赫舒『芳埃” “怎么了?”我有些...
    開封第一講書人閱讀 164,548評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵接癌,是天一觀的道長(zhǎng)心赶。 經(jīng)常有香客問我,道長(zhǎng)缺猛,這世上最難降的妖魔是什么缨叫? 我笑而不...
    開封第一講書人閱讀 58,657評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮荔燎,結(jié)果婚禮上耻姥,老公的妹妹穿的比我還像新娘。我一直安慰自己有咨,他們只是感情好琐簇,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,689評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著座享,像睡著了一般婉商。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上征讲,一...
    開封第一講書人閱讀 51,554評(píng)論 1 305
  • 那天据某,我揣著相機(jī)與錄音,去河邊找鬼诗箍。 笑死癣籽,一個(gè)胖子當(dāng)著我的面吹牛挽唉,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播筷狼,決...
    沈念sama閱讀 40,302評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼瓶籽,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了埂材?” 一聲冷哼從身側(cè)響起塑顺,我...
    開封第一講書人閱讀 39,216評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎俏险,沒想到半個(gè)月后严拒,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,661評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡竖独,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,851評(píng)論 3 336
  • 正文 我和宋清朗相戀三年裤唠,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片莹痢。...
    茶點(diǎn)故事閱讀 39,977評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡种蘸,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出竞膳,到底是詐尸還是另有隱情航瞭,我是刑警寧澤,帶...
    沈念sama閱讀 35,697評(píng)論 5 347
  • 正文 年R本政府宣布坦辟,位于F島的核電站刊侯,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏长窄。R本人自食惡果不足惜滔吠,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,306評(píng)論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望挠日。 院中可真熱鬧,春花似錦翰舌、人聲如沸嚣潜。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,898評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽懂算。三九已至,卻和暖如春庇麦,著一層夾襖步出監(jiān)牢的瞬間计技,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,019評(píng)論 1 270
  • 我被黑心中介騙來泰國打工山橄, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留垮媒,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,138評(píng)論 3 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像睡雇,于是被迫代替她去往敵國和親萌衬。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,927評(píng)論 2 355

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

  • 函數(shù)和對(duì)象 1它抱、函數(shù) 1.1 函數(shù)概述 函數(shù)對(duì)于任何一門語言來說都是核心的概念秕豫。通過函數(shù)可以封裝任意多條語句,而且...
    道無虛閱讀 4,564評(píng)論 0 5
  • 第2章 基本語法 2.1 概述 基本句法和變量 語句 JavaScript程序的執(zhí)行單位為行(line)观蓄,也就是一...
    悟名先生閱讀 4,149評(píng)論 0 13
  • 這是16年5月份編輯的一份比較雜亂適合自己觀看的學(xué)習(xí)記錄文檔混移,今天18年5月份再次想寫文章,發(fā)現(xiàn)簡(jiǎn)書還為我保存起的...
    Jenaral閱讀 2,756評(píng)論 2 9
  • 作者:盧滿麗 ①仿佛就在昨天侮穿,我剛剛踏進(jìn)城郊初中的大門沫屡,一切剛剛開始,一切都是嶄新的撮珠,一切仿佛都是美好的沮脖,一切...
    雍罡閱讀 331評(píng)論 0 3
  • 今天大寶的班里訂的一批紅色安全帽到了,征得了李老師的同意我們家委會(huì)自發(fā)的去學(xué)校給孩子們發(fā)安全帽芯急,并告訴孩子們安全的...
    金色麥穗_曉閱讀 165評(píng)論 0 1