JavaScript中的資料型別,儲存上有和差別
#前言
在JavaScript
中,我們可以分成兩種型別:
- 基本型別
- 複雜型別
兩種型別的區別是:儲存位置不同
#一、基本型別
基本型別主要為以下6種:
- Number
- String
- Boolean
- Undefined
- null
- symbol
#Number
數值最常見的整數型別格式則為十進位制,還可以設定八進位制(零開頭)、十六進位制(0x開頭)
let intNum = 55 // 10進位制的55 let num1 = 070 // 8進位制的56 let hexNum1 = 0xA //16進位制的10
浮點型別則在數值彙總必須包含小數點,還可通過科學計數法表示
let floatNum1 = 1.1; let floatNum2= 0.1; let floatNum3 = .1; // 有效,但不推薦 let floatNum = 3.125e7; // 等於 31250000
在數值型別中,存在一個特殊數值NaN
,意為“不是數值”,用於表示本來要返回數值的操作失敗了(而不是丟擲錯誤)
console.log(0/0); // NaN
console.log(-0/+0); // NaN
#Undefined
Undefined
型別只有一個值,就是特殊值undefined
。當使用var
或let
聲明瞭變數但沒有初始化時,就相當於給變數賦予了undefined
值
let message; console.log(message == undefined); //包含true
undefined
值的變數跟未定義變數是有區別的
let message; // 這個變數被聲明瞭,只是值為 undefined console.log(message); // "undefined" console.log(age); // 沒有宣告過這個變數,報錯
#String
字串可以使用雙引號(")、單引號(')或反引號(`)標示
let firstName = "John"; let lastName = 'Jacob'; let lastName = `Jingleheimerschmidt`
字串是不可變的,意思是一旦建立,它們的值就不能變了
let lang = "Java"; lang= lang + "Script"; // 先銷燬再建立
#Null
Null
型別同樣只有一個值,即特殊值null
邏輯上講, null 值表示一個空物件指標,這也是給typeof
傳一個null
會返回"object"
的原因
let car = null; console.log(typeof car); // "object"
undefined
值是由null
值派生而來
console.log(null == undefined); // true
只要變數要儲存物件,而當時又沒有那個物件可儲存,就可用null
來填充該變數
#Boolean
Boolean
(布林值)型別有兩個字面值:true
和false
通過Boolean
可以將其他型別的資料轉化成布林值
規則如下:
資料型別 轉換為 true 的值 轉換為 false 的值 String 非空字串 "" Number 非零數值(包括無窮值) 0 、 NaN Object 任意物件 null Undefined N/A (不存在) undefined
#Symbol
Symbol (符號)是原始值,且符號例項是唯一、不可變的。符號的用途是確保物件屬性使用唯一識別符號,不會發生屬性衝突的危險
let genericSymbol = Symbol(); let otherGenericSymbol = Symbol(); console.log(genericSymbol == otherGenericSymbol); // false let fooSymbol = Symbol('foo'); let otherFooSymbol = Symbol('foo'); console.log(fooSymbol == otherFooSymbol); // false
#二、引用型別
複雜型別統稱為Object
,我們這裡主要講述下面三種:
- Object
- Array
- Function
#Object
建立object
常用方式為物件字面量表示法,屬性名可以是字串或數值
let person = { name: "Nicholas", "age": 29, 5: true };
#Array
JavaScript
陣列是一組有序的資料,但跟其他語言不同的是,陣列中每個槽位可以儲存任意型別的資料。並且,陣列也是動態大小的,會隨著資料新增而自動增長
let colors = ["red", 2, {age: 20 }]
colors.push(2)
#Function
函式實際上是物件,每個函式都是Function
型別的例項,而Function
也有屬性和方法,跟其他引用型別一樣
函式存在三種常見的表達方式:
- 函式宣告
// 函式宣告 function sum (num1, num2) { return num1 + num2; }
- 函式表示式
let sum = function(num1, num2) { return num1 + num2; };
- 箭頭函式
函式宣告和函式表示式兩種方式
let sum = (num1, num2) => { return num1 + num2; };
#其他引用型別
除了上述說的三種之外,還包括Date
、RegExp
、Map
、Set
等......
#三、儲存區別
基本資料型別和引用資料型別儲存在記憶體中的位置不同:
-
基本資料型別儲存在棧中
-
引用型別的物件儲存於堆中
當我們把變數賦值給一個變數時,解析器首先要確認的就是這個值是基本型別值還是引用型別值
下面來舉個例子
#基本型別
let a = 10; let b = a; // 賦值操作 b = 20; console.log(a); // 10值
a
的值為一個基本型別,是儲存在棧中,將a
的值賦給b
,雖然兩個變數的值相等,但是兩個變數儲存了兩個不同的記憶體地址
下圖演示了基本型別賦值的過程:
#引用型別
var obj1 = {} var obj2 = obj1; obj2.name = "Xxx"; console.log(obj1.name); // xxx
引用型別資料存放在內對內中,每個堆記憶體中有一個引用地址,該引用地址存放在棧中
obj1
是一個引用型別,在賦值操作過程彙總,實際是將堆記憶體物件在棧記憶體的引用地址複製了一份給了obj2
,實際上他們共同指向了同一個堆記憶體物件,所以更改obj2
會對obj1
產生影響
下圖演示這個引用型別賦值過程
#小結
- 宣告變數時不同的記憶體地址分配:
- 簡單型別的值存放在棧中,在棧中存放的是對應的值
- 引用型別對應的值儲存在堆中,在棧中存放的是指向堆記憶體的地址
- 不同的型別資料導致賦值變數時的不同:
- 簡單型別賦值,是生成相同的值,兩個物件對應不同的地址
- 複雜型別賦值,是將儲存物件的記憶體地址賦值給另一個變數。也就是兩個變數指向堆記憶體中同一個物件
原文轉自https://github.com/febobo/web-interview