JavaSript高級程序設(shè)計(jì)-第四章學(xué)習(xí)筆記

4.1基本類型和引用類型的值

ECMASript變量可能包含兩種不同數(shù)據(jù)類型的值

graph LR
ECMAScript變量-->基本類型值
ECMAScript變量-->引用類型值

  • 基本類型值, 保存在棧內(nèi)存中的簡單數(shù)據(jù)段。Undefined, Null,Boolean,Number和String晚吞,在內(nèi)存中分別占有固定大小的空間,一般稱它們按值訪問刽宪。

  • 引用類型值摆昧,保存在堆內(nèi)存中的對象。意思是變量中保存的實(shí)際上只是一個(gè)指針峭咒,這個(gè)指針指向內(nèi)存中的另一個(gè)位置税弃,該位置保存對象。

    由于這種類型大小不固定凑队,不能保存在棧內(nèi)存當(dāng)中则果,但是它們的內(nèi)存地址是固定的,我們可以存儲(chǔ)在棧內(nèi)存當(dāng)中漩氨。當(dāng)查詢引用類型的變量時(shí)西壮,就首先從棧中讀取內(nèi)存地址,然后“順桿爬”地找到保存在堆中的值叫惊。這種方式一般稱為按“引用”訪問款青,因?yàn)槲覀儾僮鞯牟皇菍?shí)際值,而是被那個(gè)值所引用的對象霍狰。

    image

4.1.1動(dòng)態(tài)的屬性

  • 定義基本類型值和引用類型值的方式是相同的:創(chuàng)建一個(gè)變量并為其賦值
  • 當(dāng)這個(gè)值保存到變量以后:
  1. 對引用類型的值抡草,我們可以為其添加屬性和方法,也可以改變和刪除其屬性和方法
  2. 對基本類型值蔗坯,我們不能給其添加屬性(雖然添加了不會(huì)導(dǎo)致錯(cuò)誤)康震,如下,當(dāng)我們訪問添加的屬性宾濒,會(huì)發(fā)現(xiàn)該屬性不見了
var name="Mike";
name.age=27;
alert(name.age); //undefined

4.1.2復(fù)制變量值

  • 除了保存方式不同腿短,在復(fù)制變量值上也存在不同:
  1. 復(fù)制基本類型值:會(huì)在變量對象上創(chuàng)建一個(gè)新值,然后把該值復(fù)制到為新變量分配的位置上,復(fù)制后的值是原來值的一個(gè)副本答姥,此后這兩個(gè)變量可以參與任何操作而不會(huì)相互影響铣除。
  2. 復(fù)制引用類型的值:同樣會(huì)復(fù)制,但與上面不同是這個(gè)值的副本實(shí)際上是一個(gè)指針鹦付,而這個(gè)指針指向儲(chǔ)存在堆內(nèi)存中的一個(gè)對象尚粘。此后,兩個(gè)變量實(shí)際上將引用同一個(gè)對象敲长,改變其中一個(gè)變量郎嫁,會(huì)影響另一個(gè)。如下祈噪。
var obj1=new Object();
var obj2=obj1;
obj1.name="JJ";
alert(obj2.name); //JJ

4.1.3傳遞參數(shù)

  • ECMASript中所有參數(shù)都是按值傳遞泽铛。訪問變量有按值和按引用兩種方式,而參數(shù)只能按值辑鲤。
  • 傳遞參數(shù)盔腔,就是把函數(shù)外部的值復(fù)制給函數(shù)內(nèi)部的參數(shù),就和把值從一個(gè)變量復(fù)制到另一個(gè)變量一樣月褥。
  1. 向參數(shù)傳遞基本類型的值時(shí)弛随,被傳遞的值會(huì)復(fù)制給一個(gè)局部變量(即命名參數(shù)),如下:
function addTen(num){
    num+=10;
    return num;
}
var count=20;
var result=addTen(count);
alert(count); //20,沒有變化
alert(result); //30

假如num是按引用傳遞宁赤,則count的值將變成30舀透,從而反映內(nèi)部的修改,而實(shí)際并不是决左,參數(shù)是按值傳遞愕够。

  1. 向參數(shù)傳遞引用類型的值時(shí),會(huì)把這個(gè)值在內(nèi)存中的地址復(fù)制給一個(gè)局部變量佛猛,因此這個(gè)局部變量的變化會(huì)反映在函數(shù)外部惑芭,如下:
function setName(obj){
    obj.name="jj";
}
var person=new Object();
setName(person);
alert(person.name); //jj

可能有人會(huì)認(rèn)為,在局部作用域修改的對象會(huì)在全局作用域反映出來挚躯,則說明參數(shù)是按引用傳遞强衡,如下證明對象是按值傳遞:

function setName(obj){
    obj.name="jj";
    /*增加兩段代碼*/
    obj=new Object();
    obj.name="gg";
}
var person=new Object();
setName(person);
alert(person.name); //jj

如果person是按引用傳遞,則person會(huì)自動(dòng)修改為指向name屬性值為“gg”的新對象码荔,而結(jié)果不是漩勤,說明即使函數(shù)內(nèi)部修改了參數(shù)的值,但原始的引用仍然保持未變缩搅。實(shí)際上越败,當(dāng)函數(shù)內(nèi)部重寫obj時(shí),這個(gè)變量引用的就是一個(gè)局部對象了硼瓣,這個(gè)局部對象會(huì)在函數(shù)執(zhí)行完畢立即被銷毀究飞。

4.1.4檢測類型(學(xué)習(xí)第六章再看)

  • 檢查基本類型采用 typeof

  • 檢查變量是不是某引用類型的實(shí)例置谦,用instanceof


4.2執(zhí)行環(huán)境及作用域

執(zhí)行環(huán)境
  • 執(zhí)行環(huán)境,有時(shí)也稱為環(huán)境亿傅。執(zhí)行環(huán)境定義了變量或函數(shù)有權(quán)訪問的其他數(shù)據(jù)媒峡,決定了它們各自的行為。
  • 每個(gè)執(zhí)行環(huán)境都有一個(gè)與之相關(guān)聯(lián)的變量對象葵擎,環(huán)境中定義的所有變量和函數(shù)都保持在這個(gè)對象中谅阿。(我們編寫的代碼無法訪問 這個(gè)對象,但解析器在處理數(shù)據(jù)時(shí)會(huì)在后臺使用它)
  • 全局執(zhí)行環(huán)境是最外圍的一個(gè)執(zhí)行環(huán)境酬滤。web瀏覽器中签餐,全局執(zhí)行環(huán)境被認(rèn)為是window對象。
  • 某個(gè)執(zhí)行環(huán)境中的所有代碼執(zhí)行完畢后盯串,該環(huán)境被銷毀氯檐,保存在其中是所有變量和函數(shù)定義也隨之銷毀。(全局執(zhí)行環(huán)境直到應(yīng)用程序退出体捏,如關(guān)閉網(wǎng)頁或?yàn)g覽器時(shí)才被銷毀)冠摄。
  • 每個(gè)函數(shù)都有自己的執(zhí)行環(huán)境。當(dāng)執(zhí)行流入一個(gè)函數(shù)時(shí)几缭,函數(shù)的環(huán)境就會(huì)被推入一個(gè)環(huán)境棧中耗拓,而函數(shù)執(zhí)行之后,棧將其環(huán)境彈出奏司,把控制權(quán)返回給之前的執(zhí)行環(huán)境。
作用域
  • 當(dāng)代碼在一個(gè)環(huán)境中執(zhí)行時(shí)樟插,會(huì)創(chuàng)建變量對象的一個(gè)作用域鏈(scope chain)韵洋。作用域鏈的用途是保證對執(zhí)行環(huán)境有權(quán)訪問的所有變量和函數(shù)的有序訪問。
  • 作用域鏈的前端黄锤,始終都是當(dāng)前執(zhí)行的代碼所在環(huán)境的變量對象搪缨。如果這個(gè)環(huán)境是函數(shù),則將其活動(dòng)對象(activation object)作為變量對象鸵熟「北啵活動(dòng)對象在最開始時(shí)只包含一個(gè)對象,即arguments(這個(gè)對象在全局環(huán)境中是不存在的)流强。
  • 作用域鏈的下一個(gè)變量對象來自包含(外部)環(huán)境痹届,而再下一個(gè)變量對象則來自下一個(gè)包含環(huán)境。這樣一直延續(xù)到全局執(zhí)行環(huán)境打月。全局執(zhí)行環(huán)境的變量對象始終都是作用域中的最后一個(gè)對象队腐。
  • 標(biāo)識符解析是沿著作用域鏈一級一級地搜索標(biāo)識符過程。搜索過程始終從作用域鏈的前端開始奏篙,然后逐級向后回溯柴淘,直至找到標(biāo)識符為止(如果找不到標(biāo)識符,則會(huì)發(fā)生錯(cuò)誤)
  • 每個(gè)環(huán)境都可以向上搜索作用域鏈,以查詢變量和函數(shù)名为严;但任何變量都不能通過向下搜索作用域鏈而進(jìn)入另一個(gè)執(zhí)行環(huán)境敛熬。
var color="blue";
function changeColor(){
    var anotherColor="red";
    
    function swapColors(){
        var tempColor=anotherColor;
        anotherColor=color;
        color=tempColor;
        //局部作用域中定義的變量可以在局部環(huán)境中與全局變量互換使用
        //這里可以訪問color,anothercolor第股,tempColor应民;
    }
    //這里可以訪問color,anotherColor
}
//這里只能訪問color炸茧,changeColor()瑞妇;
  1. 以上代碼涉及三個(gè)執(zhí)行環(huán)境:全局環(huán)境,changeColor()的局部環(huán)境和swapColors()的局部環(huán)境梭冠。
graph LR
window-->color
window-->changeColor

changeColor-->anotherColor
changeColor-->swapColors
swapColors-->tempColor

  1. 內(nèi)部環(huán)境可以通過作用域鏈訪問所有外部環(huán)境辕狰,外部環(huán)境不能訪問內(nèi)部環(huán)境的任何變量和函數(shù)。
  2. swapColors()的作用域鏈包含三個(gè)對象:swapColors()的變量對象控漠,changeColor()的變量對象和全局變量對象蔓倍。(swapColors()的內(nèi)部可以訪問其他兩個(gè)環(huán)境中的所有變量,因?yàn)槟莾蓚€(gè)環(huán)境是它的父執(zhí)行環(huán)境盐捷;)
  3. changeColor()的作用域鏈包含兩個(gè)對象
    它自己的變量對象和全局變量對象偶翅。(不能訪問swapColors()的環(huán)境;)
  • 函數(shù)參數(shù)也被當(dāng)成變量來對待碉渡,因此其訪問規(guī)則與執(zhí)行環(huán)境中的其他變量相同聚谁。

4.2.1延長作用域鏈(看不懂)

  • try-catch語句的catch
  • with語句
  • 對catch語句來說,其變量對象中包含的是被拋出的錯(cuò)誤對象的聲明

4.2.2沒有塊級作用域

  • JavaScript沒有塊級作用域滞诺。
if(ture){
    var color="blue";
}
alert(color); //"blue"

以上代碼形导,如果在c,c++或java(有塊級作用域)习霹,color會(huì)在if語句執(zhí)行完畢后被銷毀朵耕。但在js中,if語句中的變量聲明會(huì)將變量添加到當(dāng)前的執(zhí)行環(huán)境(這里是全局環(huán)境中)淋叶,==使用for語句時(shí)要牢記這一差異==阎曹,如:

for(var i=0;i<10;i++){
    doSomething(i);
}
alert(i); //10

對有塊級作用域的語言,for語句初始化變量的表達(dá)式所定義的變量煞檩,只會(huì)存在于循環(huán)的環(huán)境中处嫌。而對于js,由for語句創(chuàng)建的變量i即使在for循環(huán)執(zhí)行結(jié)束后形娇,也依舊會(huì)存在于循環(huán)外部的執(zhí)行環(huán)境中锰霜。

  1. 聲明變量
  • 使用var聲明的變量會(huì)被自動(dòng)添加到最接近的環(huán)境中。在函數(shù)內(nèi)部桐早,最接近的環(huán)境就是函數(shù)的局部環(huán)境癣缅;在with語句中厨剪,最接近的環(huán)境是函數(shù)環(huán)境。
  • 如果初始化變量時(shí)沒有使用var聲明友存,該變量會(huì)自動(dòng)被添加到全局環(huán)境回俐。
function add(num1,num2){
    var sum=num1+num2;
    return sum;
}
var result=add(10,20); //30
alert(sum); //由于sum不是有效變量核畴,因此導(dǎo)致錯(cuò)誤

如果省略var關(guān)鍵字脯宿,那么當(dāng)add()執(zhí)行完畢后亩进,sum也將可以訪問到,因?yàn)閟um添加到了全局環(huán)境:

function add(num1,num2){
    sum=num1+num2;
    return sum;
}
var result=add(10,20); //30
alert(sum); //30
  • 建議初始化變量之前膨俐,一定要先聲明勇皇。
  1. 查詢標(biāo)識符
  • 搜索過程從作用域的前端開始,沿作用域鏈向上搜索焚刺,搜索過程一直追溯到全局環(huán)境的變量對象敛摘。如果在全局環(huán)境中也沒有找到這個(gè)標(biāo)識符,則意味該變量尚未聲明乳愉。
var color="blue";
function getColor(){
    return color;
}
alert(getColor()); //"blue",在全局環(huán)境中找到
var color="blue";
function getColor(){
    var color="red";
    return color;
}
alert(getColor()); //"red",在局部環(huán)境中找到
  • 以上例子:如果局部環(huán)境中存在著同名標(biāo)識符兄淫,就不會(huì)使用位于父環(huán)境中的標(biāo)識符

4.3垃圾收集(引用計(jì)數(shù)蔓姚?)

  1. 4.3.1標(biāo)記清除:JavaScript 中最常用的是垃圾收集方式是標(biāo)記清除( mark-and-sweep )捕虽。當(dāng)變量進(jìn)入環(huán)境時(shí),就將這個(gè)變量標(biāo)記為“進(jìn)入環(huán)境”坡脐。從邏輯上講泄私,永遠(yuǎn)不能釋放進(jìn)入環(huán)境的變量所占用的內(nèi)存,因?yàn)橹灰獔?zhí)行流進(jìn)入相應(yīng)的環(huán)境备闲,就可能會(huì)用到它們挖滤。而當(dāng)變量離開環(huán)境時(shí),則將其標(biāo)記為“離開環(huán)境”浅役。
  2. 4.3.2引用計(jì)數(shù):通過跟蹤每個(gè)值被引用的次數(shù)來清除所占用的內(nèi)存。
  • 4.3.3性能問題
  • 4.3.4管理內(nèi)存一旦數(shù)據(jù)不再有用伶唯,就將其值設(shè)置為null來釋放其引用—這個(gè)做法一般叫“解除引用”觉既,這個(gè)做法適用于大多數(shù)全局變量和全局對象的屬性。局部變量會(huì)在它們離開執(zhí)行環(huán)境時(shí)自動(dòng)被解除引用乳幸。
    不過瞪讼,解除一個(gè)值的引用并不意味著自動(dòng)回收該值所占用的內(nèi)存,而是讓值脫離執(zhí)行環(huán)境粹断,以更垃圾收集器下次運(yùn)行時(shí)將其回收符欠。

Author:YY

Date:2017.7.11

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市瓶埋,隨后出現(xiàn)的幾起案子希柿,更是在濱河造成了極大的恐慌诊沪,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,734評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件曾撤,死亡現(xiàn)場離奇詭異端姚,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)挤悉,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,931評論 3 394
  • 文/潘曉璐 我一進(jìn)店門渐裸,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人装悲,你說我怎么就攤上這事昏鹃。” “怎么了诀诊?”我有些...
    開封第一講書人閱讀 164,133評論 0 354
  • 文/不壞的土叔 我叫張陵洞渤,是天一觀的道長。 經(jīng)常有香客問我畏梆,道長您宪,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,532評論 1 293
  • 正文 為了忘掉前任奠涌,我火速辦了婚禮宪巨,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘溜畅。我一直安慰自己捏卓,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,585評論 6 392
  • 文/花漫 我一把揭開白布慈格。 她就那樣靜靜地躺著怠晴,像睡著了一般。 火紅的嫁衣襯著肌膚如雪浴捆。 梳的紋絲不亂的頭發(fā)上蒜田,一...
    開封第一講書人閱讀 51,462評論 1 302
  • 那天,我揣著相機(jī)與錄音选泻,去河邊找鬼冲粤。 笑死,一個(gè)胖子當(dāng)著我的面吹牛页眯,可吹牛的內(nèi)容都是我干的梯捕。 我是一名探鬼主播,決...
    沈念sama閱讀 40,262評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼窝撵,長吁一口氣:“原來是場噩夢啊……” “哼傀顾!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起碌奉,我...
    開封第一講書人閱讀 39,153評論 0 276
  • 序言:老撾萬榮一對情侶失蹤短曾,失蹤者是張志新(化名)和其女友劉穎寒砖,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體错英,經(jīng)...
    沈念sama閱讀 45,587評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡入撒,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,792評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了椭岩。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片茅逮。...
    茶點(diǎn)故事閱讀 39,919評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖判哥,靈堂內(nèi)的尸體忽然破棺而出献雅,到底是詐尸還是另有隱情,我是刑警寧澤塌计,帶...
    沈念sama閱讀 35,635評論 5 345
  • 正文 年R本政府宣布挺身,位于F島的核電站,受9級特大地震影響锌仅,放射性物質(zhì)發(fā)生泄漏章钾。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,237評論 3 329
  • 文/蒙蒙 一热芹、第九天 我趴在偏房一處隱蔽的房頂上張望贱傀。 院中可真熱鬧,春花似錦伊脓、人聲如沸府寒。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,855評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽株搔。三九已至,卻和暖如春纯蛾,著一層夾襖步出監(jiān)牢的瞬間纤房,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,983評論 1 269
  • 我被黑心中介騙來泰國打工翻诉, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留帆卓,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,048評論 3 370
  • 正文 我出身青樓米丘,卻偏偏與公主長得像,于是被迫代替她去往敵國和親糊啡。 傳聞我的和親對象是個(gè)殘疾皇子拄查,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,864評論 2 354

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