亚洲中字慕日产2020,大陆极品少妇内射AAAAAA,无码av大香线蕉伊人久久,久久精品国产亚洲av麻豆网站

資訊專(zhuān)欄INFORMATION COLUMN

JavaScript學(xué)習(xí)筆記 - 變量、作用域與內(nèi)存問(wèn)題

lavnFan / 3118人閱讀

摘要:語(yǔ)句中的塊語(yǔ)句對(duì)來(lái)說(shuō),將會(huì)指定對(duì)象添加到作用域鏈中。在嚴(yán)格模式下,初始化未經(jīng)聲明的變量會(huì)導(dǎo)致錯(cuò)誤。查詢(xún)標(biāo)識(shí)符搜索過(guò)程從作用域鏈的前端開(kāi)始,向上逐級(jí)查詢(xún)與給定名字匹配的標(biāo)識(shí)符。

本文記錄了我在學(xué)習(xí)前端上的筆記,方便以后的復(fù)習(xí)和鞏固。

4.1基本類(lèi)型和引用類(lèi)型的值

ECMAScript變量可能包含兩種不同數(shù)據(jù)類(lèi)型的值:基本類(lèi)型值和引用類(lèi)型值?;绢?lèi)型指的是簡(jiǎn)單的數(shù)據(jù)段,而引用類(lèi)型值指那些可能由多個(gè)值構(gòu)成的對(duì)象。

數(shù)據(jù)類(lèi)型:

基本類(lèi)型值:Undefined、Null、Boolean、Number、String;

引用類(lèi)型值,也就是對(duì)象類(lèi)型:Object、Array、Function、Date等;

聲明變量時(shí)不同的內(nèi)存分配

基本類(lèi)型值:存儲(chǔ)在棧(stack)中的簡(jiǎn)單數(shù)據(jù)段,它們的值直接存儲(chǔ)在變量訪(fǎng)問(wèn)的位置。這是因?yàn)檫@些基本類(lèi)型占據(jù)的空間是固定的,所以可以將它們存儲(chǔ)在較小的內(nèi)存區(qū)域 - 棧中。這樣存儲(chǔ)更便于迅速查尋變量的值。

引用值:存儲(chǔ)在堆(heap)中的對(duì)象,也就是說(shuō),存儲(chǔ)在變量處的值是一個(gè)指針(point),指向存儲(chǔ)對(duì)象的內(nèi)存地址。這是因?yàn)椋?b>引用值的大小會(huì)改變,所以不能把它放在中,否則會(huì)降低變量查尋的速度。相反,放在變量的棧空間中的值是該對(duì)象存儲(chǔ)在中的地址。地址的大小是固定的,所以把它存儲(chǔ)在中對(duì)變量性能無(wú)任何負(fù)面影響。

不同的內(nèi)存分配機(jī)制也帶來(lái)了不同的訪(fǎng)問(wèn)機(jī)制

javascript中是不允許直接訪(fǎng)問(wèn)保存在堆內(nèi)存中的對(duì)象的,也就是說(shuō)不能直接操作對(duì)象的內(nèi)存空間。所以在訪(fǎng)問(wèn)一個(gè)對(duì)象時(shí),首先得到的是這個(gè)對(duì)象在堆內(nèi)存中的地址,然后再按照這個(gè)地址去獲得這個(gè)對(duì)象中的值,這就是傳說(shuō)中的按引用訪(fǎng)問(wèn)。而原始類(lèi)型的值則是可以直接訪(fǎng)問(wèn)到的。

注意:當(dāng)復(fù)制保存著對(duì)象的某個(gè)變量時(shí),操作的事對(duì)象的引用。但在為對(duì)象添加屬性時(shí),操作的是實(shí)際的對(duì)象

復(fù)制變量的不同

基礎(chǔ)類(lèi)型值:在將一個(gè)保存著基礎(chǔ)類(lèi)型值的變量復(fù)制給另一個(gè)變量時(shí),會(huì)將原始值的副本賦值給新變量,此后這兩個(gè)變量是完全獨(dú)立的,他們只是擁有相同的value而已。

function addTen(num) {
    num += 10;
    return num;
}
var count = 20;
var result = addTen(count);
console.log(count); //20 沒(méi)有變化
console.log(result); //30

引用值:在將一個(gè)保存著對(duì)象內(nèi)存地址的變量復(fù)制給另一個(gè)變量時(shí),會(huì)把這個(gè)內(nèi)存地址賦值給新變量,也就是說(shuō)這兩個(gè)變量都指向了堆內(nèi)存中的同一個(gè)對(duì)象,他們中任何一個(gè)作出的改變都會(huì)反映在另一個(gè)身上。(這里要理解的一點(diǎn)就是,復(fù)制對(duì)象時(shí)并不會(huì)在堆內(nèi)存中新生成一個(gè)一模一樣的對(duì)象,只是多了一個(gè)保存指向這個(gè)對(duì)象指針的變量罷了)

function setName(obj) {
    obj.name = "Nicholas";
}
var person = new Object();
setName(person);
console.log(person.name); //"Nicholas"
參數(shù)傳遞的不同

首先我們應(yīng)該明確一點(diǎn):ECMAScript中所有函數(shù)的參數(shù)都是按值來(lái)傳遞的。但是為什么涉及到基礎(chǔ)類(lèi)型與引用類(lèi)型的值時(shí)仍然有區(qū)別呢,還不就是因?yàn)閮?nèi)存分配時(shí)的差別。

基礎(chǔ)類(lèi)型值:只是把變量里的值傳遞給參數(shù),之后參數(shù)和這個(gè)變量互不影響。

引用類(lèi)型值:對(duì)象變量它里面的值是這個(gè)對(duì)象在堆內(nèi)存中的內(nèi)存地址,這一點(diǎn)你要時(shí)刻銘記在心!因此它傳遞的值也就是這個(gè)內(nèi)存地址,這也就是為什么函數(shù)內(nèi)部對(duì)這個(gè)參數(shù)的修改會(huì)體現(xiàn)在外部的原因了,因?yàn)樗鼈兌贾赶蛲粋€(gè)對(duì)象呀?;蛟S我這么說(shuō)了以后你對(duì)書(shū)上的例子還是有點(diǎn)不太理解,那么請(qǐng)看圖吧:

所以,如果是按引用傳遞的話(huà),是把第二格中的內(nèi)容(也就是變量本身)整個(gè)傳遞進(jìn)去(就不會(huì)有第四格的存在了)。但事實(shí)是變量把它里面的值傳遞(復(fù)制)給了參數(shù),讓這個(gè)參數(shù)也指向原對(duì)象。因此如果在函數(shù)內(nèi)部給這個(gè)參數(shù)賦值另一個(gè)對(duì)象時(shí),這個(gè)參數(shù)就會(huì)更改它的值為新對(duì)象的內(nèi)存地址指向新的對(duì)象,但此時(shí)原來(lái)的變量仍然指向原來(lái)的對(duì)象,這時(shí)候他們是相互獨(dú)立的;但如果這個(gè)參數(shù)是改變對(duì)象內(nèi)部的屬性的話(huà),這個(gè)改變會(huì)體現(xiàn)在外部,因?yàn)樗麄児餐赶虻倪@個(gè)對(duì)象被修改了呀!來(lái)看下面這個(gè)例子吧:(傳說(shuō)中的call by sharing)

var obj1 = {
  value:"111"
};
 
var obj2 = {
  value:"222"
};
 
function changeStuff(obj){
  obj.value = "333";
  obj = obj2;       
  return obj.value;
}
 
 
var foo = changeStuff(obj1);
 
console.log(foo);// "222" 參數(shù)obj指向了新的對(duì)象obj2
console.log(obj1.value);//"333"

obj1仍然指向原來(lái)的對(duì)象,之所以value改變了,
是因?yàn)?b>changeStuff里的第一條語(yǔ)句,這個(gè)時(shí)候obj是指向obj1的 .
再啰嗦一句,如果是按引用傳遞的話(huà),這個(gè)時(shí)候obj1.value應(yīng)該是等于"222"

可以把ECMAScript函數(shù)的參數(shù)想象成局部變量

4.1.4 檢測(cè)類(lèi)型

如果變量的值是一個(gè)對(duì)象null,則typeof操作符會(huì)返回"object".

通常我們并不是想知道某個(gè)值是對(duì)象,而是想知道它是什么類(lèi)型的對(duì)象。為此,ECMAScript提供了instanceof操作符;

如果對(duì)象是給定引用類(lèi)型的實(shí)例,那么instanceof操作符就會(huì)返回true。

console.log(person instanceof Object);  //變量person是Object嗎?
console.log(colors instanceof Array);   //變量colors是Array嗎?
console.log(pattern instanceof RegExp); //變量pattern是RegExp嗎?

根據(jù)規(guī)定,所有引用類(lèi)型的值都是Object的實(shí)例。在檢查一個(gè)引用類(lèi)型值和Object構(gòu)造函數(shù)時(shí),instanceof操作符始終會(huì)返回true。

4.2執(zhí)行壞境和作用域

每個(gè)函數(shù)都有自己的執(zhí)行環(huán)境。當(dāng)執(zhí)行流進(jìn)入一個(gè)函數(shù)時(shí),函數(shù)的環(huán)境就會(huì)被推入一個(gè)環(huán)境棧中。而在函數(shù)執(zhí)行后,將其環(huán)境彈出,把控制權(quán)返回給之前的執(zhí)行環(huán)境。

每個(gè)環(huán)境都有一個(gè)與之關(guān)聯(lián)的變量對(duì)象,環(huán)境中定義的所有變量和函數(shù)都保存在這個(gè)對(duì)象中。雖然我們編寫(xiě)的代碼無(wú)法訪(fǎng)問(wèn)這個(gè)對(duì)象,但解析器在處理數(shù)據(jù)時(shí)會(huì)在后臺(tái)使用它

當(dāng)代碼在一個(gè)環(huán)境執(zhí)行時(shí),會(huì)創(chuàng)建變量對(duì)象的一個(gè)作用域鏈。作用域鏈的用途,是保證對(duì)執(zhí)行環(huán)境有權(quán)訪(fǎng)問(wèn)的所有變量和函數(shù)的有序訪(fǎng)問(wèn)

4.2.1 延長(zhǎng)作用域鏈

有些語(yǔ)句可以在作用域鏈的前端臨時(shí)增加一個(gè)變量對(duì)象,該變量對(duì)象會(huì)在代碼執(zhí)行后被移除。有兩種情況下會(huì)發(fā)生這種現(xiàn)象。

try-catch 語(yǔ)句中的 catch 塊

with 語(yǔ)句

對(duì) with 來(lái)說(shuō),將會(huì)指定對(duì)象添加到作用域鏈中。對(duì) catch 來(lái)說(shuō),會(huì)創(chuàng)建一個(gè)新的變量對(duì)象,其中包含的是被拋出的錯(cuò)誤對(duì)象的聲明。

var oMyself = {
    sFirstname: "Aidan",
    sLastName: "Dai"
}

function create(){
    var sLastName = "Wen"
    with(oMyself){
        //將oMyself作為自己的執(zhí)行環(huán)境
        sAllName = sFirstname +" " + sLastName;
    }
    return sAllName;
}
var sMyName = create();
console.log(sMyName); //Aidan Dai
4.2.2 沒(méi)有塊級(jí)作用域

對(duì)于有塊級(jí)作用域的語(yǔ)言來(lái)說(shuō),for語(yǔ)句初始化變量的表達(dá)式所定義的變量,只會(huì)存在于循環(huán)的環(huán)境之中。而對(duì)于JavaScript來(lái)說(shuō),由for語(yǔ)句創(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語(yǔ)句中,最接近的環(huán)境就是函數(shù)環(huán)境。如果初始化變量時(shí)沒(méi)有使用var聲明,該變量會(huì)自動(dòng)被添加到全局環(huán)境。

注意:在編寫(xiě)JavaScript中,不聲明而直接初始化變量時(shí)一個(gè)錯(cuò)誤的做法,因?yàn)檫@樣可能會(huì)導(dǎo)致意外。在嚴(yán)格模式下,初始化未經(jīng)聲明的變量會(huì)導(dǎo)致錯(cuò)誤。

2.查詢(xún)標(biāo)識(shí)符
搜索過(guò)程從作用域鏈的前端開(kāi)始,向上逐級(jí)查詢(xún)與給定名字匹配的標(biāo)識(shí)符。如果在局部環(huán)境找到,搜索過(guò)程停止,變量就緒。如果在局部環(huán)境中沒(méi)有找到該變量名,則繼續(xù)沿作用域向上搜索。搜索過(guò)程將一直追溯到全局環(huán)境的變量對(duì)象。在全局環(huán)境也沒(méi)找到的話(huà)則說(shuō)明該變量尚未聲明。

var color = "blue";

function getColor() {
    return color;
}

console.log(getColor()); //"blue";
4.3 垃圾收集

JavaScript具有自動(dòng)垃圾收集機(jī)制,也就是說(shuō),執(zhí)行環(huán)境會(huì)負(fù)責(zé)管理代碼執(zhí)行過(guò)程中使用的內(nèi)存。
JavaScript垃圾回收的機(jī)制很簡(jiǎn)單:找出不再使用的變量,然后釋放掉其占用的內(nèi)存,但是這個(gè)過(guò)程不是時(shí)時(shí)的,因?yàn)槠溟_(kāi)銷(xiāo)比較大,所以垃圾回收器會(huì)按照固定的時(shí)間間隔周期性的執(zhí)行。

變量生命周期

什么叫不再使用的變量?不再使用的變量也就是生命周期結(jié)束的變量,當(dāng)然只可能是局部變量,全局變量的生命周期直至瀏覽器卸載頁(yè)面才會(huì)結(jié)束。局部變量只在函數(shù)的執(zhí)行過(guò)程中存在,而在這個(gè)過(guò)程中會(huì)為局部變量在?;蚨焉戏峙湎鄳?yīng)的空間,以存儲(chǔ)它們的值,然后再函數(shù)中使用這些變量,直至函數(shù)結(jié)束(閉包中由于內(nèi)部函數(shù)的原因,外部函數(shù)并不能算是結(jié)束

一旦函數(shù)結(jié)束,局部變量就沒(méi)有存在必要了,可以釋放它們占用的內(nèi)存。貌似很簡(jiǎn)單的工作,為什么會(huì)有很大開(kāi)銷(xiāo)呢?這僅僅是垃圾回收的冰山一角,就像剛剛提到的閉包,貌似函數(shù)結(jié)束了,其實(shí)還沒(méi)有,垃圾回收器必須知道哪個(gè)變量有用,哪個(gè)變量沒(méi)用,對(duì)于不再有用的變量打上標(biāo)記,以備將來(lái)回收。用于標(biāo)記無(wú)用的策略有很多,常見(jiàn)的有兩種方式

4.3.1 標(biāo)記清除

這是JavaScript最常見(jiàn)的垃圾回收方式,當(dāng)變量進(jìn)入執(zhí)行環(huán)境的時(shí)候,比如函數(shù)中聲明一個(gè)變量,垃圾回收器將其標(biāo)記為“進(jìn)入環(huán)境”,當(dāng)變量離開(kāi)環(huán)境的時(shí)候(函數(shù)執(zhí)行結(jié)束)將其標(biāo)記為“離開(kāi)環(huán)境”。至于怎么標(biāo)記有很多種方式,比如特殊位的反轉(zhuǎn)、維護(hù)一個(gè)列表等,這些并不重要,重要的是使用什么策略,原則上講不能夠釋放進(jìn)入環(huán)境的變量所占的內(nèi)存,它們隨時(shí)可能會(huì)被調(diào)用的到。

垃圾回收器會(huì)在運(yùn)行的時(shí)候給存儲(chǔ)在內(nèi)存中的所有變量加上標(biāo)記,然后去掉環(huán)境中的變量以及被環(huán)境中變量所引用的變量(閉包),在這些完成之后仍存在標(biāo)記的就是要?jiǎng)h除的變量了,因?yàn)榄h(huán)境中的變量已經(jīng)無(wú)法訪(fǎng)問(wèn)到這些變量了,最后,垃圾收集器完成內(nèi)存清除工作,銷(xiāo)毀那些帶標(biāo)記的值并回收它們所占用的內(nèi)存空間。

4.3.2 引用計(jì)數(shù)

在低版本IE中經(jīng)常會(huì)出現(xiàn)內(nèi)存泄露,很多時(shí)候就是因?yàn)槠洳捎靡糜?jì)數(shù)方式進(jìn)行垃圾回收。引用計(jì)數(shù)的策略是跟蹤記錄每個(gè)值被使用的次數(shù),當(dāng)聲明了一個(gè)變量并將一個(gè)引用類(lèi)型賦值給該變量的時(shí)候這個(gè)值的引用次數(shù)就加1,如果該變量的值變成了另外一個(gè),則這個(gè)值得引用次數(shù)減1,當(dāng)這個(gè)值的引用次數(shù)變?yōu)?的時(shí)候,說(shuō)明沒(méi)有變量在使用,這個(gè)值沒(méi)法被訪(fǎng)問(wèn)了,因此可以將其占用的空間回收,這樣垃圾回收器會(huì)在運(yùn)行的時(shí)候清理掉引用次數(shù)為0的值占用的空間。

4.3.3 性能問(wèn)題

垃圾收集器是周期性運(yùn)行的,而且如果為變量分配的內(nèi)存數(shù)量很可觀,那么回收工作量也是相當(dāng)大的。在這種情況下,確定垃圾收集的時(shí)間間隔是一個(gè)非常重要的問(wèn)題。

事實(shí)上,在有的瀏覽器中可以觸發(fā)垃圾收集過(guò)程,但我們不建議這樣做。在IE中調(diào)用window.CollectGarbage()方法會(huì)立即執(zhí)行垃圾收集。在Opera7及更高版本中,調(diào)用window.opera.collect()也會(huì)啟動(dòng)垃圾收集例程。

4.3.4管理內(nèi)存

確保占用最少的內(nèi)存可以讓頁(yè)面獲得更好的性能。而優(yōu)化內(nèi)存占用的最佳方式,就是為執(zhí)行中的代碼只保存必要數(shù)據(jù)。一旦數(shù)據(jù)不再可用,最好通過(guò)將其值設(shè)置為null來(lái)釋放其引用——這個(gè)方法叫做解除引用(dereferencing)。這一做法適用于大多數(shù)全局變量和全局對(duì)象屬性。局部變量會(huì)在它們離開(kāi)執(zhí)行環(huán)境時(shí)自動(dòng)被解除引用。

function createPerson(name) {
     var localPerson = new Object();
     localPerson.name = name;
     return localPerson;
}
var globalPerson = createPerson("Nicholas");

//手工解除globalPerson的引用

globalPerson = null;
4.4 小結(jié)

基本類(lèi)型值和引用類(lèi)型值具有以下特點(diǎn):

基本類(lèi)型值在內(nèi)存中占據(jù)固定大小的空間,因此被保存在棧內(nèi)存中;

從一個(gè)變量向另一個(gè)變量復(fù)制基本類(lèi)型的值,會(huì)創(chuàng)建這個(gè)值得一個(gè)副本;

引用類(lèi)型的值是對(duì)象,保存在堆內(nèi)存中;

包含引用類(lèi)型值得變量實(shí)際上包含的并不是對(duì)象本身,而是指向該對(duì)象的指針;

從一個(gè)變量向另一個(gè)變量復(fù)制引用類(lèi)型的值,復(fù)制的其實(shí)是指針,因此兩個(gè)變量最終都指向同一個(gè)對(duì)象;

確定一個(gè)值是哪種基本類(lèi)型可以使用typeof操作符,而確定一個(gè)值是哪種引用類(lèi)型可以使用instanceof操作符。
所有變量(包括基本類(lèi)型和引用類(lèi)型)都存在于一個(gè)執(zhí)行環(huán)境(也稱(chēng)為作用域)當(dāng)中,這個(gè)執(zhí)行環(huán)境決定了變量的生命周期,以及哪一部分代碼可以訪(fǎng)問(wèn)其中的變量。

最后,如有錯(cuò)誤和疑惑請(qǐng)指出,多謝各位大哥

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/82338.html

相關(guān)文章

  • 《你不知道的javascript筆記_作用域與閉包

    摘要:建筑的頂層代表全局作用域。實(shí)際的塊級(jí)作用域遠(yuǎn)不止如此塊級(jí)作用域函數(shù)作用域早期盛行的立即執(zhí)行函數(shù)就是為了形成塊級(jí)作用域,不污染全局。這便是閉包的特點(diǎn)吧經(jīng)典面試題下面的代碼輸出內(nèi)容答案?jìng)€(gè)如何處理能夠輸出閉包方式方式下一篇你不知道的筆記 下一篇:《你不知道的javascript》筆記_this 寫(xiě)在前面 這一系列的筆記是在《javascript高級(jí)程序設(shè)計(jì)》讀書(shū)筆記系列的升華版本,旨在將零碎...

    galaxy_robot 評(píng)論0 收藏0
  • 你不知道的JavaScript上卷之作用域與閉包·讀書(shū)筆記

    摘要:的分句會(huì)創(chuàng)建一個(gè)塊作用域,其聲明的變量?jī)H在中有效。而閉包的神奇作用是阻止此事發(fā)生。依然持有對(duì)該作用域的引用,而這個(gè)引用就叫做閉包。當(dāng)然,無(wú)論使用何種方式對(duì)函數(shù)類(lèi)型的值進(jìn)行傳遞,當(dāng)函數(shù)在別處被調(diào)用時(shí)都可以觀察到閉包。 date: 16.12.8 Thursday 第一章 作用域是什么 LHS:賦值操作的目標(biāo)是誰(shuí)? 比如: a = 2; RHS:誰(shuí)是賦值操作的源頭? 比如: conso...

    Raaabbit 評(píng)論0 收藏0
  • 先有蛋還是先有雞?JavaScript 作用域與閉包探析

    摘要:而閉包的神奇之處正是可以阻止事情的發(fā)生。拜所聲明的位置所賜,它擁有涵蓋內(nèi)部作用域的閉包,使得該作用域能夠一直存活,以供在之后任何時(shí)間進(jìn)行引用。依然持有對(duì)該作用域的引用,而這個(gè)引用就叫閉包。 引子 先看一個(gè)問(wèn)題,下面兩個(gè)代碼片段會(huì)輸出什么? // Snippet 1 a = 2; var a; console.log(a); // Snippet 2 console.log(a); v...

    elisa.yang 評(píng)論0 收藏0
  • javaScript作用域與閉包

    摘要:閉包里面保存的變量只有被方法引用了的變量這個(gè)例子里,閉包里只有并沒(méi)有。那最后來(lái)說(shuō)說(shuō)的問(wèn)題閉包到底是什么閉包是一個(gè)作用域。鑒于在的調(diào)試窗口,是放在下面的那閉包這個(gè)作用域是個(gè)什么范圍被后代方法子方法,孫子方法。。。 首先給js的作用域這個(gè)話(huà)題打標(biāo)簽:2,var, 全局變量,局部變量,函數(shù),undefined, 作用域提升,賦值不會(huì)提升,ReferenceError, 同名覆蓋。打完標(biāo)簽之后...

    Reducto 評(píng)論0 收藏0
  • JavaScript語(yǔ)法理論知識(shí)點(diǎn)

    摘要:方法用于刪除原數(shù)組中的一部分元素,并可以在被刪除的位置添加新數(shù)組成員,返回值是被刪除的元素。遞歸函數(shù)函數(shù)內(nèi)部調(diào)用函數(shù)自身,稱(chēng)之為遞歸。在函數(shù)內(nèi)使用聲明的變量是局部變量,是人為的聲明。 前言 這個(gè)筆記不知道什么時(shí)候記下的反正很有意思,很基礎(chǔ),很理論。 JavaScript學(xué)習(xí)筆記1 第一章 JavaScript概述 1.1 什么是JavaScript JavaScript是一種輕量級(jí)的腳...

    Amos 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<