JavaScript系列----數據類型以及傳值和傳引用 對象基於哈希存儲(之Key篇(1) JavaScript系列-----對象基於哈希存儲(之Valu

1.簡單數據類型

  在JavaScript中簡單數據類型分爲5種。分別爲 Undefined, Null,Boolean,Number,String.html

  • Undefined類型
    Undefined類型只有一個值,即特殊的undefined。在使用var對變量聲明的時候,變量的值即被初始化爲undefined.
    在使用typeof求得數據類型的時候,對於未聲明的變量返回的老是undefined.

  • Null類型
    Null也只有一個值得數據類型,其實質是一個指向空對象的指針。因此使用typeof操做的時候返回的是一個object類型。
    var object = null; console.log(typeof object);//object
    實際上,Undefined派生自Null類型。因此,Ecma-262規範中,null==undefined //值爲true.

  • Boolean類型
    Boolean類型只有兩個值ture或者false.

  • Number類型
    Number數據類型有幾個比較常使用的數值常量。
      
      (1)最大值: Number.MAX_VALUE.
      (2)最小值: NUMBER.MIN_VALUE.
        (3)正無窮大: Infinity
      (4)負無窮大: -Infinity
        (5)非數字   :NaN.

    數值轉換:
    數值轉換有三種常見的函數:Number, ParseInt, ParseFloat
    Number經常使用於轉型函數,然後兩種經常使用於字符串轉數值。

  • String類型
    基本數據類型中,最複雜的一種也就是字符串了。

      字符串的特色:
      (1).單雙引號報過均可。
      (2).字符串不可變。
         什麼是字符串不可變?      程序員

 var str1="hello"; //開闢一份新空間 var str2="world"; //開闢一份新空間 str1=str1+str2;  //由於字符串的不可變特性,改變字符串會從新開闢一份新空間,之前的那一份在一段時間後被垃圾回收機制回收。 console.log(str1);         做爲基本數據類型,字符串做爲函數參數的時候是傳值仍是傳引用呢?

    若是傳值:   則必須複製一份新的字符串做爲參數。字符串若是太長的話,很明顯,浪費空間。
    若是傳引用: 字符串做爲參數,若是值沒有改變,則不須要開闢新的空間。
           若是值改變,又由於字符串不可變的特性而會從新開闢新的空間。

           因此,字符串在做爲參數的時候是傳引用而非傳值。數組

                  注: 關於傳值仍是傳引用,咱們這裏參照物均爲變量自己。------詳情請看第三部分。數據結構

2.複雜數據類型  

  複雜數據類型也就是咱們常說的引用類型.引用類型是一種數據結構,其值也就是其所指向的對象。
  ECMAScript提供了不少原生態的引用類型。
函數

  • Object類型
        (1)兩種建立方式
    • //第一種,使用構造函數。
      var  object=new Object();
      object.name="xxxx";
      
      
      //第二種,使用字面量的建立方式,程序員更傾向於第二種
      var object={ 
             name:"xxxx"  
      }

(2) 對象的屬性post


Object數據類型的對象是採用鬆散的結構組織屬性的。所謂的鬆散,就是咱們所說的用鍵值對來保存對象。而鍵值對以hash表結構存儲。this

有關於對象以鍵值對存儲的文章,詳情見對象基於哈希存儲(<Key,Value>之Key篇(1)url

     Object類型的對象,屬性能夠分爲兩類:spa

      a.數據屬性3d

        數據屬性有四個描素其行爲的特性。  

      1. [Configurable]:表示是否能夠經過delete刪除該屬性,可否修改屬性的特性。
        var object = { name: '張三' }; Object.defineProperty(object, 'name', { configurable: false }); delete object.name;  //false

        Object.defineProperty(object, 'name', {
        configurable: true
        });    //error:TypeError: can't redefine non-configurable property 'name'

      2. [Enumerale]:表示該屬性是否能夠經過for-in循環遍歷
        var object = {
          name: '張三',
          age:18
        };
        Object.defineProperty(object, 'name', {
          configurable: false,
          enumerable: false
        });
        for (var property in object) {
          console.log(property);    //age
        }

         

      3. [Writable]:表示該屬性的值是否能被更改
        var object = { name: '張三', age: 18 }; Object.defineProperty(object, 'name', { configurable: false, enumerable: false, writable: false }); object.name = '李四'; console.log(object.name);//張三,name未被更改
      4. [Value]:保存屬性的值,寫入屬性的時候,將屬性的值保存在此位置;讀取此屬性的時候,從該值中讀取。
        var object = { name: '張三' }; Object.defineProperty(object, 'age', { configurable: false, enumerable: false, writable: false, value: 18 }); console.log(object.age);//18         
          

b.訪問器屬性:訪問器屬性不包含數據值,但其包含getter和setter函數。其也有四個特徵值對其進行描述

      1. [Configurable]:表示是否能夠經過delete刪除該屬性,可否修改屬性的特性。
      2. [Enumerale]:表示該屬性是否能夠經過for-in循環遍歷。
      3. [Get]:在讀取屬性時,調用的函數。
        var object = { name: '張三', age: 18 }; Object.defineProperty(object, 'isAdult', { configurable: false, enumerable: false, get: function () { if (this.age < 18) { return false; } else { return true; } } }); console.log(object.isAdult);//true isAdult就是一個訪問器屬性
      4. [Set]:在寫入屬性時調用的函數
        var object = { name: '張三', age: 18 }; Object.defineProperty(object, 'changeAge', { configurable: false, enumerable: false, set: function (value) { this.age = value; } }); object.changeAge=17; console.log(object.age);//17

  (3)對象的經常使用方法

    •  toString():返回對象的字符串形式。
    •  valuOf():該方法取得對象的基本數據類型。通常返回的是個數值。 其與toString()方法的區別,詳請見JavaScript系列-----對象基於哈希存儲(<Key,Value>之Value篇) (3)
    •  hasOwnProperty(attrName):判斷對象中是否有某一個屬性,且該屬性不在對象的原型對象上。
    •  Object.getOwnPropertyNames(object):返回一個數組,數組中保存着對象object中的全部屬性名,且該屬性不在原型對象上。  


  • Array類型
    (1)定義:數組對象用來在單獨的變量名中存儲一系列的值。
    (2)建立方式:
    //第一種 使用構造函數
    var mycars=new Array() mycars[0]="Saab" mycars[1]="Volvo" mycars[2]="BMW" 或者 var mycars=new Array("Saab","Volvo","BMW") //第二種 使用數組字面量
    var  colors=["red","blue","green"]; 
    (3)數組的屬性
      
    length:數組的 length 屬性老是比數組中定義的最後一個元素的下標大 1,經過length 屬性可設置或返回數組中元素的數目。
    var array=[]; array[100]=10; console.log(array.length);//101

    array=[1,2,3,4,5];
    array.length=3;
    console.log(array);//1,2,3

  • Date類型

    建立方式:


    • var myDate=new Date(); //Date 對象自動使用當前的日期和時間做爲其初始值。
       補充說明:對於時間  其月份老是從0開始算起,即月份表示 0---11.而其餘的和咱們正常所理解的是一致的。
  •  函數類型(參見本系列第四篇函數篇
  • RegExp類型(在下一篇文章中做爲專題)

  3.傳值和傳引用 

      (1)問題的起源

   其實這個問題來源於C和C++,由於C或C++裏都有一個特殊的數據類型----指針,那時候所謂的傳值和傳引用是對指針來講的。
那麼針對指針來講,
什麼是傳值,又什麼是傳引用呢?首先,指針做爲一種數據類型,其自己確定是佔用必定的內存空間,並且,指針同時還要指向另外一塊內存空間。

      如圖所示:

    針對指針來講,指針做爲一種數據類型,指針的標識符也就是其在內存中所在的地址,指針的值就是其所指向的地址。也就是說,指針值是地址。
那麼一個指針在做爲函數的參數的時候,傳給參數的究竟是指針的地址仍是指針的值呢? ----這就是傳值和傳引用問題的起源.

    (2)指針的傳值和傳引用
           
函數的參數,在函數被調用的時候,在其函數所開闢的那個棧中是佔用必定的內存空間的,那麼這塊內存空間的值是什麼呢?

首先,先確定一點,形參的值來源確定是實參。那麼,實參給形參賦值的時候傳的是什麼呢?

          (1)傳的是結構體地址,那麼就如圖所示:

                

 

  若是傳的是結構體的地址,那麼也就是指針的值賦值給形參。因此,這就是咱們所謂的傳值。由圖中咱們能夠看出,若是是傳值的話,那麼做爲形參的指針和做爲實參的指針,指向的是同一個結構體。

      
    
 (2)若是傳的是指針的地址,那麼指針的地址就會賦值給形參。結果,如圖所示:
        

  對於傳引用來講,形參的值是指針的地址,那麼每次對形參的改變,其實改變的都是指針所指向的地址。而若是向取得結構體的地址,也須要經過實參的地址。
    

(3)JS中只存在傳值

首先須要明確一寫概念,即引用和對象的概念。

引用:也就是咱們所說的指針,其存在於棧中。

對象:也就是上圖中咱們所標記的結構體,其存在於堆中。

引用的值就是對象所在的地址。咱們用一個例子說明: 

var person = {
  name: '張三',
  age: 18
};
function setName(object) {
  object.name = '王五';
}
setName(person);
console.log(person.name);//王五

 依然用圖來解釋:

 

從上圖中咱們能夠看書,函數在傳參是,傳的是實參的值,也就是指針的值。咱們,咱們這裏理解爲傳值。

可是,換一種角度來講,把對象看成參照物,傳給形參的值就是對象的地址,也並不是對象自己,說是傳引用也不爲過。

因此,不管是傳值仍是傳引用,只要理解了便可。不必糾結於字眼。

 

(4)基本數據類型傳值

首先基本數據類型與引用數據類型相比的差異就是,基本數據類型保存在函數運行時的棧中,而引用數據類型的值保存在堆空間中。那麼,若是基本數據類型給形參賦值的時候是怎樣的呢?

舉個例子:

var x = 1;
function add(num) {
  return num + 1;
}
add(1);

 x做爲實參,num做爲函數的形參,當函數add被調用時,形參num被賦值爲實參x的值。即 num=1;結構圖以下所示:

如上如所示,此時對形參的值作任何改變均與實參無關,實參和形參是兩個互不關聯的個體。

 

補充一點: 字符串也是一種數據類型,那麼字符串的值保存在哪裏呢? 其做爲函數參數的時候,傳值是如何進行的呢?

字符串雖然也是一種基本數據類型,但由於其大小不固定,因此,其通常其更像與引用數據類型。但其又有其特殊性----不可變性。

  什麼是字符串的不可變?

var str="";
for(var i=0;i<3;i++){
str+=i;
}
console.log(str);//012  

 

     看上圖程序,字符串是能夠改變的。那爲何還要說,字符串不可變呢,先別急,咱們來分析一下程序運行時內存結構圖。

          

 

 

 

 

 

 

 

 

 

         

        看到沒有,每一次字符串值的改變,其所指向的地址都會跟着改變一次。其所說的不可變,是跟引用數據類型相比來講,引用數據類型值的改變通常是對象自己的改變,而其指向是不變的,而字符串值的改變是其指向地址的改變。因此,字符串的每一次改變都會產生垃圾,此垃圾過一段時間會被垃圾回收機制回收。

瞭解了上述的狀況,因此字符傳在做爲參數的時候,爲了節省空間,只是複製了字符串所指向的地址給形參,而形參的值若是改變了的話,由於字符串具備不可變特性,因此會從新開闢一份空間給形參。以下

var str = '你是誰?';
function change(str) {
  str = '我就是我了';
}
change(str);
console.log(str);//你是誰
 

 

   

 

 字符串在Java C++中均做爲比較特殊的一種類型,JS中雖然將其看成一種基本數據類型,可是其使用時更偏向於引用數據類型,可是其又具備不可變型,才促使咱們能夠將其看成基本數據類型使用。

相關文章
相關標籤/搜索