国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

js中的值類型、引用類型、堆、棧、函數(shù)參數(shù)傳遞方式、連續(xù)賦值等概念的學(xué)習(xí)

hizengzeng / 1854人閱讀

摘要:值類型基本類型和棧內(nèi)存值類型也稱為原始數(shù)據(jù)或原始值這類值存儲在棧內(nèi)存中基本類型的值不可以修改。目前中的基本類型一共有六種。堆的使用規(guī)則當(dāng)創(chuàng)建數(shù)組時(shí),就會在堆內(nèi)存中創(chuàng)建一個(gè)數(shù)組對象,并且在棧內(nèi)存中創(chuàng)建一個(gè)對數(shù)組的引用。

值類型(基本類型)和棧內(nèi)存

值類型也稱為原始數(shù)據(jù)或原始值(primitive value).這類值存儲在棧(stack)內(nèi)存中, 基本類型的值不可以修改。每當(dāng)我們定義一個(gè)變量,并賦給它一個(gè)基本類型的值時(shí),可以理解為,我們?yōu)檫@個(gè)變量綁定了一個(gè)內(nèi)存空間,這個(gè)內(nèi)存空間存放的就是變量的值。因此。基本類型數(shù)據(jù)是存放在棧內(nèi)存中的簡單數(shù)據(jù)段,數(shù)據(jù)大小確定,內(nèi)存空間大小可以分配。
目前js中的基本類型一共有六種:null,undefined,boolean,number,,string,symbol。其中symbol是es6中新加的數(shù)據(jù)類型。這些類型在內(nèi)存中分別占用固定大小的空間,他們的值保存在棧空間,我們通過按值來訪問的、
讓我們看一個(gè)基本類型的值不可以修改的示例

var a = 4;
a = 3; //注意,這里是覆蓋,不是修改

var num1 = 5;
var num2 = num1;

num1+=1;
consol.log(num1);//6
console.log(num2);//5

從上面第二個(gè)例子可以看到,從一個(gè)變量向另一個(gè)變量復(fù)制基本類型的值,我們會在變量對象上重新創(chuàng)建一個(gè)新值,然后把值復(fù)制到新變量分配的位置上,這兩個(gè)值是完全獨(dú)立的,對著兩個(gè)變量進(jìn)行操作是互不影響的。

引用類型

這類值存儲在堆內(nèi)存中,堆是內(nèi)存中的動態(tài)區(qū)域,相當(dāng)于自留空間,在程序運(yùn)行期間會動態(tài)分配給代碼和堆棧。對中存儲的一般都是對象,然后在棧內(nèi)存中存儲一個(gè)變量指針,計(jì)算機(jī)通過這個(gè)變量指針,找到堆中的數(shù)據(jù)塊并進(jìn)行操作。這種訪問方式,我們叫它按引用訪問。如圖所示。

堆的使用規(guī)則
var fruit_1 = "apple";
var fruit_2 = "orange";
var fruit_3 = "banana";
var oArray = [fruit_1,fruit_2,fruit_3];
var newArray = oAarray;

當(dāng)創(chuàng)建數(shù)組時(shí),就會在堆內(nèi)存中創(chuàng)建一個(gè)數(shù)組對象,并且在棧內(nèi)存中創(chuàng)建一個(gè)對數(shù)組的引用。變量fruit_1、fruit_2、fruit_3為基本數(shù)據(jù)類型,他們的值直接存放在棧中;newArray、oArray為符合數(shù)據(jù)類型(引用類型),他們的引用變量存放在棧中,指向于存放在堆中的實(shí)際對象。
此時(shí)我們改變oAarray中的值,對應(yīng)的newArray也會改變,因?yàn)樗鼈兊拇鎯Φ闹羔樦赶蛲粋€(gè)堆地址。

console.log(oArray[1]);// 返回 orange
newArray[1]="berry";
console.log(oArray[1]);// 返回 berry

例如,下面代碼將newArray賦值為null:

newArray = null;

注意:接觸一個(gè)值的引用并不意味著自動回收改值所占用的內(nèi)存。解除引用的真正作用時(shí)讓值脫離執(zhí)行環(huán)境,以便垃圾收集器下次運(yùn)行時(shí)將其回收。

為什么會有棧內(nèi)存和堆內(nèi)存之分?

與垃圾回收機(jī)制有關(guān),為了使程序運(yùn)行時(shí)占用的內(nèi)存最小。
當(dāng)一個(gè)方法執(zhí)行時(shí),每個(gè)方法都會建立自己的內(nèi)存棧,在這個(gè)方法內(nèi)定義的變量會逐個(gè)放入這塊棧內(nèi)存里,隨著方法的執(zhí)行結(jié)束,這個(gè)方法的內(nèi)存棧也將自然銷毀了。因此,所有在方法中定義的變量都是放在棧內(nèi)存中的;
當(dāng)我們在程序中創(chuàng)建一個(gè)對象時(shí),這個(gè)對象將被保存到運(yùn)行時(shí)數(shù)據(jù)區(qū)中,以便反復(fù)理由(因?yàn)閷ο蟮膭?chuàng)建成本通常比較大),這個(gè)運(yùn)行時(shí)數(shù)據(jù)區(qū)就是堆內(nèi)存。堆內(nèi)存中的對象不會隨方法的結(jié)束而銷毀,即使方法結(jié)束后,這個(gè)對象還可能被另一個(gè)引用變量所引用(方法的參數(shù)傳遞時(shí)很常見),則這個(gè)對象依然不會被銷毀,只有當(dāng)一個(gè)對象沒有任何引用變量引用它時(shí),系統(tǒng)的垃圾回收機(jī)制才會在核實(shí)的時(shí)候回收它。

函數(shù)中參數(shù)傳遞方式,按值傳遞和按引用傳遞

按值傳遞:函數(shù)的形參時(shí)被調(diào)用時(shí)所傳實(shí)參的副本,修改形參并不會影響實(shí)參。

var num = 10;
function change(num){
    num = num * 10;
}
change(num)
console.log(num);       // 2

可以看到這里的變量num在運(yùn)行完函數(shù)以后,值并沒有發(fā)生改變。

按引用傳遞:函數(shù)的形參接收實(shí)參的內(nèi)存地址,而不再是副本。這意味著函數(shù)形參的值如果被修改,實(shí)參也會被修改。

var ab={
    x:1,
    y:2
}

function foo(obj){
    obj.x = 2
}
foo(ab)

console.log(ab);    //{x:2,y:2}

可以看到,原來的ab對象,在函數(shù)foo調(diào)用之后,其中的對象屬性發(fā)生變化。由上面的兩個(gè)例子,我們是不是可以推斷在js中,對于基本類型的數(shù)據(jù),在函數(shù)傳遞過程中使用的時(shí)按值傳遞,而對于引用類型數(shù)據(jù),在函數(shù)傳遞過程中使用的時(shí)是按引用傳遞方式呢?讓我們再看另外一個(gè)例子。

var ab={
    x:1,
    y:2
}

function foo(obj){
    obj = {
        x:2,
        y:3
    }
}
foo(ab)

console.log(ab);    //{x:1,y:2}

這個(gè)示例,如果按照我們剛剛說的結(jié)論,這里的函數(shù)運(yùn)行后,輸出的對象ab的值應(yīng)該是{x:2,y:3}。但是真正的結(jié)果確實(shí){x:1,y:2}。這就奇怪了,到底js中的函數(shù)參數(shù)的傳遞方式是按什么樣的方式呢。我在網(wǎng)上找了很多資料,發(fā)現(xiàn)有個(gè)說法叫按共享傳遞。簡單來說,就是對于基本類型,是按值傳遞,對于對象而言,直接修改形參對實(shí)參沒有效果,而修改形參的屬性卻可以同時(shí)修改實(shí)參的屬性。而我的理解是這樣的。看一張圖。

由我們上面對引用類型與堆內(nèi)存的介紹,我們知道,當(dāng)我們定義一個(gè)ab對象時(shí),系統(tǒng)會在堆中開出一個(gè)空間用來存儲改對象,對應(yīng)的在棧內(nèi)存中開出一個(gè)空間,用來存儲指向?qū)ο蟮牡刂贰H缟蠄D,根據(jù)按引用傳遞的方式,我們知道,foo函數(shù)內(nèi)部的obj。在函數(shù)編譯的時(shí)候,是指向ab所指向的對象的,二者共用一個(gè)地址。當(dāng)函數(shù)執(zhí)行后,obj指向了新的對象地址,但是之前的ab所指向的對象屬性,依舊被ab所引用,沒有任何改變。所以,這里輸出的ab的值依舊未變。
而對于函數(shù)內(nèi)部,改變形參的屬性值這個(gè)情況,我們也可以很容易的清楚,因?yàn)楹瘮?shù)內(nèi)部的obj和ab對象共同指向同一個(gè)對象空間,所以改變前者的對象屬性的值,自然會影響后者

一道經(jīng)典的面試題
var a = {n:1};
var b = a;

a.x = a = {n:2};
console.log(a.x);
console.log(b.x)

這道題考察了很多東西,js中的運(yùn)算符的優(yōu)先級,比如賦值運(yùn)算,是從右到左的。js中的對象存儲的問題。但是這道題很容易根據(jù)賦值運(yùn)算是從右到左的順序運(yùn)行的來得到錯誤的結(jié)果

a = {n:2}
a.x = a

然后得到了錯誤的答案。a.x = {n:2}.實(shí)際上,要解出這道題,我們至少要知道兩個(gè),第一個(gè)就是運(yùn)算符的優(yōu)先級問題,點(diǎn)運(yùn)算符的優(yōu)先級高于賦值運(yùn)算級。所以這里的執(zhí)行順序第一步肯定是a.x,然后才是從右到左的賦值運(yùn)算;第二個(gè),我們要知道的是,js對象在內(nèi)存中是如何存儲的。知道這兩點(diǎn),那這道題就不難解決了。同樣的,我們繼續(xù)看幾張圖。

通過該題的前兩行代碼的聲明a和b,結(jié)合上面所說的對象存儲的原理,可以很容易看明白。a和b指向同一個(gè)對象空間。

a.x = a = {n:2}

這行代碼,首先會運(yùn)行a.x。這樣便會在{n:1}對象所存儲的空間上添加一個(gè)x屬性名,并且等待賦值。即原來的{n:1}變成{n:1,x:undefined}。然后,按照賦值運(yùn)算的順序,先將變量a的指向變?yōu)閧n:2},但是這里要注意,{n:1,x:undefined}由于被b引用,所以依舊存在在內(nèi)存當(dāng)中。然后執(zhí)行 ax.x = a,這里要注意,這里的a已經(jīng)是{n:2}了。而a.x則是b指向的{n:1,x:undefined}中的x屬性,所以最終b指向的{n:1,x:undefined}變?yōu)閧n:1,x:{n:2}}。
所以最后的結(jié)果。看下圖。

console.log(a.x);   //undefined
console.log(b.x);   //{n:2}


參考鏈接:
https://www.imooc.com/article...
https://blog.csdn.net/lxiang2...
https://blog.csdn.net/xdd1991...
https://segmentfault.com/a/11...
https://blog.csdn.net/u012860...

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

轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/97561.html

相關(guān)文章

  • 第二章 一切都是對象

    摘要:此內(nèi)存區(qū)域的唯一目的就是存放對象實(shí)例,幾乎所有的對象實(shí)例都在這里分配內(nèi)存。不過,無論如何劃分,都與存放內(nèi)容無關(guān),無論哪個(gè)區(qū)域,存儲的都仍然是對象實(shí)例,進(jìn)一步劃分的目的是為了更好地回收內(nèi)存,或者更快地分配內(nèi)存。 一、對象和類的存儲 根據(jù)java虛擬機(jī)規(guī)范第七版的規(guī)定,Java虛擬機(jī)所管理的內(nèi)存將包括以下幾個(gè)運(yùn)行時(shí)數(shù)據(jù)區(qū)域:程序計(jì)數(shù)器、方法區(qū)、堆、虛擬機(jī)棧、本地方法棧。(詳見深入理解jav...

    孫吉亮 評論0 收藏0
  • 前端進(jìn)擊巨人(二):、隊(duì)列、內(nèi)存空間

    摘要:中有三種數(shù)據(jù)結(jié)構(gòu)棧堆隊(duì)列。前端進(jìn)擊的巨人一執(zhí)行上下文與執(zhí)行棧,變量對象中解釋執(zhí)行棧時(shí),舉了一個(gè)乒乓球盒子的例子,來演示棧的存取方式,這里再舉個(gè)栗子搭積木。對于基本類型,棧中存儲的就是它自身的值,所以新內(nèi)存空間存儲的也是一個(gè)值。 面試經(jīng)常遇到的深淺拷貝,事件輪詢,函數(shù)調(diào)用棧,閉包等容易出錯的題目,究其原因,都是跟JavaScript基礎(chǔ)知識不牢固有關(guān),下層地基沒打好,上層就是豆腐渣工程,...

    edgardeng 評論0 收藏0
  • ?搞不懂JS賦值·淺拷貝·深拷貝請看這里

    showImg(https://segmentfault.com/img/bVbvpCA); 前言 為什么寫拷貝這篇文章?同事有一天提到了拷貝,他說賦值就是一種淺拷貝方式,另一個(gè)同事說賦值和淺拷貝并不相同。我也有些疑惑,于是我去MDN搜一下拷貝相關(guān)內(nèi)容,發(fā)現(xiàn)并沒有關(guān)于拷貝的實(shí)質(zhì)概念,沒有辦法只能通過實(shí)踐了,同時(shí)去看一些前輩們的文章總結(jié)了這篇關(guān)于拷貝的內(nèi)容,本文也屬于公眾號【程序員成長指北】學(xué)習(xí)路線...

    lauren_liuling 評論0 收藏0
  • JavaScript學(xué)習(xí)總結(jié)(一)基礎(chǔ)部分

    摘要:前綴規(guī)范每個(gè)局部變量都需要有一個(gè)類型前綴,按照類型可以分為表示字符串。例如,表示以上未涉及到的其他對象,例如,表示全局變量,例如,是一種區(qū)分大小寫的語言。布爾值與字符串相加將布爾值強(qiáng)制轉(zhuǎn)換為字符串。 基本概念 javascript是一門解釋型的語言,瀏覽器充當(dāng)解釋器。js執(zhí)行時(shí),在同一個(gè)作用域內(nèi)是先解釋再執(zhí)行。解釋的時(shí)候會編譯function和var這兩個(gè)關(guān)鍵詞定義的變量,編譯完成后從...

    AlanKeene 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<