D1-數據型別詳解和堆疊記憶體

2020-08-14 11:06:36
詳細解讀JS中的9大數據型別

數據型別分類
+ 基本數據型別 【7】
+ 參照數據型別 【2】
+ isNaN、NaN、Infinity

學習之前先來看一道面試題,看下這道題是否能做對。

let res = parseFloat('left:200px');
if(res===200){
   alert(200);
}else if(res===NaN){
   alert(NaN);
}else if(typeof res==='number'){
   alert('number');
}else{
   alert('Invalid Number');
}
  • 基本數據型別(原始值型別):
    • number NaN/Infinity
    • string 單引號/雙引號/反引號``
    • boolean true/false
    • null
    • undefined
    • symbol 建立唯一值【比較重要】
    • bigint 【瞭解即可】
  • 參照數據型別:
    • object
      • {} 普通物件
      • [] 陣列物件
      • /^ [+ -]?(?:\d|(?:[1-9]\d+))(.\d+)?$/ 正則物件
      • 日期物件
      • 數學物件
    • function

typeof 是按照二進制的底層機制 機製來檢測數據型別的,預設以000開頭的都是物件,而null全是0,所以把null看作物件數據型別。

結合程式碼詳解上述知識點:

  1. Number數據型別中的特殊點–NaN:not a number 不是一個有效數位,但是它屬於number數據型別的
//NaN是數位型別,不是有效數位
console.log(typeof NaN); //=>"number"

//NaN和任何值都不相等,包括它自己
console.log(NaN == NaN); //=>false

//想要判斷一個值是否爲NaN,用方法isNaN([val])
let n = 10;
if (isNaN(n)) {
    // 條件成立:證明它真的是非有效數位
}

//Object.is([val1],[val2]):檢測兩個值是否相等
console.log(Object.is(NaN, NaN)); //=>true

Object.is([val1],[val2]):檢測兩個值是否相等,返回一個 Boolean 型別標示兩個參數是否是同一個值。
Object.is() 方法判斷兩個值是否爲同一個值。如果滿足以下條件則兩個值相等:

  • 都是 undefined
  • 都是 null
  • 都是 true 或 false
  • 都是相同長度的字串且相同字元按相同順序排列
  • 都是相同對象(意味着每個物件有同一個參照)
  • 都是數位且
    —— 都是 +0
    —— 都是 -0
    —— 都是 NaN
    —— 或都是非零而且非 NaN 且爲同一個值

與== 運算不同。 == 運算子在判斷相等前對兩邊的變數(如果它們不是同一型別) 進行強制轉換 (這種行爲的結果會將 「」 == false 判斷爲 true), 而 Object.is不會強制轉換兩邊的值。
與=== 運算也不相同。 === 運算子 (也包括 == 運算子) 將數位 -0 和 +0 視爲相等 ,而將Number.NaN 與NaN視爲不相等.

  1. 唯一值Symbol
let val = Symbol('00');
console.log(val == val); //=>true

console.log(Symbol('AA') == Symbol('AA')); //=>false

let a = NaN;
console.log(a == a); //=>false
  1. BigInt

JS中超過這個最大安全數之後再計算就不準 不準確了,如下圖:
在这里插入图片描述

Number.MAX_SAFE_INTEGER;//=>9007199254740991

JS中的最大安全數,超過這個值的,需要用bigint處理(在一個數值後面加n就是bigint型別)
在这里插入图片描述
現在來看下最開始的面試題,相信你一定得出正確答案了,就是【‘number’】。

JS底層執行機制 機製之堆(Heap)棧(Stack)
  • ECStack(Execution [ˌeksɪˈkjuːʃn] Context Stack)和 EC(Execution Context )
  • GO(Global Object)
  • VO(Varibale Object)
  • 變數賦值的步驟

首先思考下:數據型別爲啥分成兩大型別,兩種型別有啥區別?
先來看一道面試題,由此題來引申出思考題的答案

var a = 12;
var b = a;
b = 13;
console.log(a); //12

var a = {
    n: 12
};
var b = a;
b.n = 13;
console.log(a.n);

var a = {
    n: 12
};
var b = a;
b = {
    n: 13
};
console.log(a.n);

圖解一:

var a = 12;
var b = a;
b = 13;
console.log(a); //12

在这里插入图片描述
圖解二:

var a = {
    n: 12
};
var b = a;
b.n = 13;
console.log(a.n);

在这里插入图片描述
圖解三:

var a = 12;
var b = a;
b = 13;
console.log(a); //12

在这里插入图片描述

  • 第一:JS程式碼可以執行的環境:

    • 瀏覽器(引擎/內核)
    • node.js
    • webview
  • 第二:瀏覽器之所以能夠執行程式碼,是因爲提供了-個供程式碼執行的環境,即棧記憶體 ECStack(Execution Context Stack),棧記憶體就是在計算機中分配出來的一塊記憶體

  • 第三:程式碼執行分爲:全域性程式碼、函數中程式碼、私有塊中的程式碼…
    不同環境下的程式碼執行的時候都有自己的上下文(環境)——EC(Execution Context)執行上下文

  • 第四:當前環境上下文形成後會有一個進棧的過程【JS程式碼在瀏覽器中執行,首先瀏覽器開闢一個棧記憶體即 ESCStack執行環境棧;全域性程式碼在執行前先形成自己的EC即執行上下文,這個執行上下文形成後會有一個進棧過程即進入瀏覽器分配的這塊記憶體[ECStack:執行環境棧],函數執行的時候同理】

  • 第五:程式碼在當前上下文中執行的時候,建立的變數總會儲存在當前上下文中指定的變數物件[VO (Varibale Object)]中,所以變數物件就是用來儲存當前上下文中建立的變數的。

  • 第六:程式碼執行之前先進行變數提升/詞法解析……

  • 第七:等號賦值的詳細過程:var a=12;.

    1. 建立一個值12,把它儲存起來(基本型別值是直接儲存在棧記憶體中的)
    2. 宣告一個變數,把它儲存到當前上下文所屬的變數物件中.
    3. 最後進行等號賦值(定義) :本質也是一個指針指向的過程

var a;宣告變數,但是在變數提升階段並沒有賦值,所以是未定義,預設值是undefined。等號每次賦值都會重新建立一個值。

  • 第八:如果是參照數據型別的值:
    1. 不會直接儲存在棧記憶體中,他會開闢一個堆記憶體(也是計算機記憶體中分配的一個空間),用來儲存自己的鍵值對,每一個堆記憶體都有一個16進位制的地址
    2. 在堆記憶體中分別儲存鍵值對
    3. 把16進位制的地址放到棧中,供變數呼叫

【基本數據型別是按值操作[在棧記憶體中],參照數據型別都是按照地址來操作[堆記憶體中]】

  • 連等賦值:a=b=10;=>[先b=10;再a=10]連等賦值一般以右側先運算[連等賦值只建立一次10],但是某些操作的優先順序很高,比如a.x成員存取,它的優先順序是19,比等號賦值高很多,所以優先計算它a.x=10;
    最後一起來看幾道相關練習題:
  1. 第一題
//example 1
var a={}, b='0', c=0;  
a[b]='你好';
a[c]='世界';  
console.log(a[b]);
​
---------------------

//example 2
var a={}, b=Symbol('1'), c=Symbol('1');  
a[b]='你好';
a[c]='世界';  
console.log(a[b]);
​
---------------------

//example 3
var a={}, b={n:'1'}, c={m:'2'};  
a[b]='你好';
a[c]='世界';  
console.log(a[b]);
  1. 第二題
var a = {n: 1};
var b = a;
a.x = a = {n: 2};
console.log(a.x);
console.log(b);
  1. 第三題
var x = [12, 23];
function fn(y) {
    y[0] = 100;
    y = [100];
    y[1] = 200;
    console.log(y);
}
fn(x);
console.log(x);