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

數(shù)據(jù)類型

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

兩種訪問方式

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

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

函數(shù)參數(shù)的傳遞
1、ECMA中所有函數(shù)的參數(shù)都是按值傳遞的
在向參數(shù)傳遞基本類型的值時,被傳遞的值會被復(fù)制給一個局部變量,在向參數(shù)傳遞引用類型的值時,會把這個值在內(nèi)存的地址復(fù)制給一個局部變量
基本數(shù)據(jù)類型傳遞參數(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ù)。這時addTen的參數(shù)num可以看做是函數(shù)內(nèi)部的一個變量。
在上段代碼中,就相當(dāng)于兩個基本數(shù)據(jù)類型變量之間的值復(fù)制。而基本數(shù)據(jù)類型都有自己獨立的內(nèi)存地址,所以numcount是沒有任何關(guān)系的,他們只是值相等而已,函數(shù)執(zhí)行完畢后,count的值并沒有改變。
而函數(shù)外面的result是被直接賦值的,所以result的值就是函數(shù)的結(jié)果30。

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

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

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

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

兩種變量類型檢測

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

補充:基本包裝類型(包裝對象)
先看下以下代碼:

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

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

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

所以當(dāng)?shù)诙写a訪問s1的時候,后臺會自動完成下列操作:

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

正因為有第三步這個銷毀的動作,所以基本數(shù)據(jù)類型不可以添加屬性和方法,這也正是基本裝包類型和引用類型主要區(qū)別:對象的生存期。

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

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容