JavaScript那些事--✪--變量的誕生到結束

1. 數據類型

JS的數據類型分

  • 基本類型(String、Number、Boolean、Null、Undefined)
  • 引用類型
屬性 基本類型 引用類型
定義 簡單的數據段 可能有多個值構成的對象
可以操作保存在內存中的實際值 保存在內存中的對象,按引用訪問
動態屬性 undefined 可以添加屬性/方法(people.name)

2. 變量的創建

變量:將值賦給某個東西,這個東西就叫~

  • 靜態類型(強制類型):聲明一個變量存放指定類型的值。eg:java
  • 動態類型(弱類型):允許一個變量在任何時刻修改成任何類型的值。eg:javascript

TypeScript 相對於 JavaScript ,提供了靜態類型,提高程序正確性。(但筆者認爲,如果不出現類型錯誤的情況下,動態類型在任何時刻反而更加靈活)

大概說說JS引擎進行編譯的步驟

  1. 分詞/詞法分析(eg:var a =1會分解成var、a、=、2,這些代碼塊稱詞法單元)
  2. 解析/語法分析(將詞法單元流【數組】轉換成一個由元素逐級嵌套所組成的代表了程序語法的結構樹即 “抽象語法樹”【AST】
  3. 代碼生成(將AST轉換成可執行代碼的過程)
    a. 引擎每一次遇到聲明,它就把聲明傳到作用域創建一個綁定。並且對每個聲明的變量進行分配內存,默認值爲undefined。
  // 聲明一個名字a,值爲1
  let a = 1 

創建變量過程

  1. 創建了一個名字a,用來保存後面的值
  2. 設置變量a的作用範圍(作用域)
  3. 在預處理階段會被提到函數頂部,此時a爲undefined【聲明提升–變量都是undefined,函數則是該方法,其他會報錯XX is not defined】
  4. 最後區分不同數據類型進行賦值:
    a. 基本類型把值直接保存在變量中
    b. 引用類型把對象保存在計算機內存中,同時創建訪問內存的地址即引用,把引用保存到變量中

總結:變量的賦值操作會執行兩個動作,首先編譯器會在當前作用域中聲明一個變量(如 果之前沒有聲明過),然後在運行時引擎會在作用域中查找該變量,如果能夠找到就會對 它賦值。

3. 不同類型變量複製原理

基本類型變量複製原理

對於 基本類型的變量來說,兩個變量之間可以 參與任何操作而不相互影響
存在棧中。

  let a = 6
  let b = a
  b = 8 
  console.log(b) // 8
  console.log(a) // 6

在這裏插入圖片描述

引用類型變量複製原理

對於引用類型變量,複製實際上是指針指向存儲在堆中的一個對象,改變其中一個變量,就會影響另一個變量。

  let person1 = {
    name: '小明'
  }
  let person2 = person1
  person2.name = '小紅'
  console.log(person1.name) // 小紅
  console.log(person2.name) // 小紅

在這裏插入圖片描述

ECMAScript中所有函數的參數都是按值傳遞的。【參數會複製給一個局部變量(arguments對象的一個元素),在參數傳遞引用類型的時候,會把這個值在內存中的地方複製給這個局部變量,因此這個局部變量的改變也會影響函數外部】

4. 檢測變量類型

typeof 操作符是檢測類型最佳的操作,但是對Object對象不友善。
採用 instanceof 操作符可以區分檢測object類型。

兩者結合纔是最好驗證類型的方法

 // typeof
  let genre;
  console.log(typeof genre) // undefined
  genre = 'haha'
  console.log(typeof genre) // string
  genre = 33
  console.log(typeof genre) // number
  genre = NaN
  console.log(typeof genre) // number
  genre = true
  console.log(typeof genre) // boolean
  genre = undefined
  console.log(typeof genre) // undefined
  genre = null
  console.log(typeof genre) // object
  genre = { name: 'cere', gender: 'man' }
  console.log(typeof genre) // object
  genre = [1, 2, 3]
  console.log(typeof genre) // object
  genre = function () { console.log(1) }
  console.log(typeof genre) // function

  // instanceof
  genre = null
  console.log(genre instanceof Object) // false
  genre = { name: 'cere', gender: 'man' }
  console.log(genre instanceof Object) // true
  genre = [1, 2, 3]
  console.log(genre instanceof Array) // true

注意幾點

  • typeof null返回的是object,這個應該算JS的bug,但似乎不會修改(太多代碼依賴這個bug,修改導致大量問題)
  • NAN 是number類型

null與undefined區別可以參考鏈接:阮一峯談undefined與null的區別

5. 垃圾收集

爲什麼要有垃圾收集機制

之前我們提到過創建變量,或者複製給其他變量等操作的時候都會分配一份內存。如果代碼越來越壯大,程序運行起來會申請大量的內存空間,如果不及時清理,內存會使用完(內存溢出),導致程序崩潰

JS的垃圾收集機制

JavaScript不用手工跟蹤內存情況,它的自動垃圾收集機制,可以實現自動管理無用內存。垃圾收集器會按照固定的時間間隔,週期性的執行,找到不再繼續使用的變量,然後釋放佔用的內存。

JS垃圾收集策略

垃圾收集器跟蹤變量並且判斷有沒有用,如果沒用則在標籤打上標記,以備垃將來收回佔用的空間。
垃圾收集的策略有很多種,比如標記清除,引用計數,循環引用,分代回收等。瀏覽器中的實現基本上都是標記清除(或類似策略),只不過垃圾收集的間隔互不相同。

標記清除(mark-and-sweep)

原理:當變量進入環境(比如函數中聲明一個變量),將這個變量標記(可以用任何方式標記)爲“進入環境”,此時內存佔有。而當變量離開環境時候,標記爲“離開環境”,然後等待垃圾收集器下次完成內存清楚工作,銷燬帶標記的值並回收它們所戰友的內存空間。

引用計數(reference counting)

引用計數的含義是跟蹤記錄每個值被引用的次數。當賦給其他值或其他操作的時候,引用次數不斷加1。相反,如果包含對這個值引用的變量又取得了另外一個值,則這個值的引用次數就減1。當這個引用次數變成0時,則說明沒有辦法再訪問這個值,將其所佔的內存空間給收回來。

阮老師JavaScript 內存泄漏教程

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章