JS基本數(shù)據(jù)類(lèi)型和引用數(shù)據(jù)類(lèi)型的區(qū)別

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

  1. ECMAScript變量包含兩種不同類(lèi)型的值:基本類(lèi)型值、引用類(lèi)型值;
  2. 基本類(lèi)型值:指的是保存在內(nèi)存中的簡(jiǎn)單數(shù)據(jù)段;
  3. 引用類(lèi)型值:指的是那些保存在內(nèi)存中的對(duì)象,意思是,變量中保存的實(shí)際上只是一個(gè)指針,這個(gè)指針指向內(nèi)存堆中實(shí)際的值;

兩種訪問(wèn)方式

  1. 基本類(lèi)型值:按值訪問(wèn),操作的是他們實(shí)際保存的值;
  2. 引用類(lèi)型值:按引用訪問(wèn),當(dāng)查詢(xún)時(shí),我們需要先從棧中讀取內(nèi)存地址,然后再順藤摸瓜地找到保存在堆內(nèi)存中的值;

兩種類(lèi)型復(fù)制
基本類(lèi)型變量的復(fù)制:
從一個(gè)變量向一個(gè)變量復(fù)制時(shí),會(huì)在棧中創(chuàng)建一個(gè)新值,然后把值復(fù)制到為新變量分配的位置上,改變?cè)磾?shù)據(jù)不會(huì)影響到新的變量(互不干涉);
引用類(lèi)型變量的復(fù)制:
復(fù)制的是存儲(chǔ)在棧中的指針,將指針復(fù)制到棧中為新變量分配的空間中,而這個(gè)指針副本和原指針執(zhí)行存儲(chǔ)在堆中的同一個(gè)對(duì)象,復(fù)制操作結(jié)束后,兩個(gè)變量實(shí)際上將引用同一個(gè)對(duì)象;因此改變其中的一個(gè),將影響另一個(gè)

函數(shù)參數(shù)的傳遞
1、ECMA中所有函數(shù)的參數(shù)都是按值傳遞的
在向參數(shù)傳遞基本類(lèi)型的值時(shí),被傳遞的值會(huì)被復(fù)制給一個(gè)局部變量,在向參數(shù)傳遞引用類(lèi)型的值時(shí),會(huì)把這個(gè)值在內(nèi)存的地址復(fù)制給一個(gè)局部變量
基本數(shù)據(jù)類(lèi)型傳遞參數(shù)

  funciton addTen(num){
    num+=10;
    return num;
  }
  var count=20;
  var result=addTen(count);
  alert(count);//20
  alert(resullt);//30

執(zhí)行結(jié)果是:20和30。
在這段代碼中,將變量count當(dāng)做參數(shù)傳遞給了函數(shù)addTen,也就是相當(dāng)于將變量count的值復(fù)制給了函數(shù)addTen的參數(shù)。這時(shí)addTen的參數(shù)num可以看做是函數(shù)內(nèi)部的一個(gè)變量。
在上段代碼中,就相當(dāng)于兩個(gè)基本數(shù)據(jù)類(lèi)型變量之間的值復(fù)制。而基本數(shù)據(jù)類(lèi)型都有自己獨(dú)立的內(nèi)存地址,所以numcount是沒(méi)有任何關(guān)系的,他們只是值相等而已,函數(shù)執(zhí)行完畢后,count的值并沒(méi)有改變。
而函數(shù)外面的result是被直接賦值的,所以result的值就是函數(shù)的結(jié)果30。

引用類(lèi)型傳遞參數(shù)

  function setName(obj){
    obj.name="LSN";
  }
  var person=new Object();
  setName(person);
  alert(person.name); // LSN

執(zhí)行結(jié)果是:LSN。
在這段代碼中,函數(shù)setName的作用是給obj對(duì)象添加了一個(gè)屬性name,并給該屬性賦值為"LSN",因?yàn)?code>obj是引用類(lèi)型,所以這里屬于是將引用類(lèi)型person賦值給了obj,也就是說(shuō)personobj引用了一個(gè)內(nèi)存地址,所以當(dāng)給obj新加了屬性name時(shí),在函數(shù)外面的person也跟著改變,最后person.name的結(jié)果為L(zhǎng)SN。

引用類(lèi)型傳遞參數(shù)到底傳的是值還是引用

  function setName(obj){
    obj.name="ABC";
    obj=new Object();
    obj.name="BCD";
  }
  var person=new Object();
  setName(person);
  alert(person.name); // ABC

執(zhí)行結(jié)果是:ABC。
實(shí)例3與實(shí)例2的區(qū)別是在函數(shù)中又加了2行代碼,在給obj對(duì)象新加一個(gè)屬性name并賦值后又將obj定義成了一個(gè)新的對(duì)象(new Object()),定義新對(duì)象后又name賦上新的值“BCD”。
這個(gè)時(shí)候如果是按引用傳遞的話(huà),那么最后person對(duì)象就會(huì)自動(dòng)修改為指向其name屬性為"BCD"的新對(duì)象,但最后顯示的卻是“ABC”,這說(shuō)明即使在函數(shù)內(nèi)部修改了參數(shù)的值,但原始的引用還保持不變。
實(shí)際上,當(dāng)在函數(shù)內(nèi)部obj=new Object()時(shí) 這個(gè)新的obj就已經(jīng)成為函數(shù)內(nèi)部的局部對(duì)象了,這個(gè)對(duì)象會(huì)在函數(shù)執(zhí)行完畢后自動(dòng)銷(xiāo)毀。

兩種變量類(lèi)型檢測(cè)

  1. typeof操作符是檢測(cè)基本類(lèi)型的最佳工具;
  2. 如果變量值是nul或者對(duì)象,typeof 將返回“object”;
  3. Instanceof用于檢測(cè)引用類(lèi)型,可以檢測(cè)到具體的,它是什么類(lèi)型的實(shí)例;
  4. 如果變量是給定引用類(lèi)型的實(shí)例,instanceof操作符會(huì)返回true;

補(bǔ)充:基本包裝類(lèi)型(包裝對(duì)象)
先看下以下代碼:

var s1 = "helloworld";
var s2 = s1.substr(4);

上面我們說(shuō)到字符串是基本數(shù)據(jù)類(lèi)型,不應(yīng)該有方法,那為什么這里s1可以調(diào)用substr()呢?
ECMAScript還提供了三個(gè)特殊的引用類(lèi)型BooleanStringNumber。我們稱(chēng)這三個(gè)特殊的引用類(lèi)型為基本包裝類(lèi)型,也叫包裝對(duì)象

也就是說(shuō)當(dāng)讀取stringbooleannumber這三個(gè)基本數(shù)據(jù)類(lèi)型的時(shí)候,后臺(tái)就會(huì)創(chuàng)建一個(gè)對(duì)應(yīng)的基本包裝類(lèi)型對(duì)象,從而讓我們能夠調(diào)用一些方法來(lái)操作這些數(shù)據(jù).

所以當(dāng)?shù)诙写a訪問(wèn)s1的時(shí)候,后臺(tái)會(huì)自動(dòng)完成下列操作:

  • 創(chuàng)建String類(lèi)型的一個(gè)實(shí)例;// var s1 = new String("helloworld");
  • 在實(shí)例上調(diào)用指定方法;// var s2 = s1.substr(4);
  • 銷(xiāo)毀這個(gè)實(shí)例;// s1 = null;

正因?yàn)橛械谌竭@個(gè)銷(xiāo)毀的動(dòng)作,所以基本數(shù)據(jù)類(lèi)型不可以添加屬性和方法,這也正是基本裝包類(lèi)型和引用類(lèi)型主要區(qū)別:對(duì)象的生存期

使用new操作符創(chuàng)建的引用類(lèi)型的實(shí)例,在執(zhí)行流離開(kāi)當(dāng)前作用域之前都是一直保存在內(nèi)存中。自動(dòng)創(chuàng)建的基本包裝類(lèi)型的對(duì)象,則只存在于一行代碼的執(zhí)行瞬間,然后立即被銷(xiāo)毀。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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