原文連結我的blog。
為什麼說“ JavaScript 萬物皆物件?”,這個“萬物”,難道真的是“萬物”?
其實不然。
在 JavaScript 中一共有七種主要型別:
- String
- Number
- Boolean
- Null
- Undefined
- Symbol
- Object
前六種為基本資料型別,Object 為引用型別(物件型別),值得注意一點的是用 typeof null
會返回 Object
,這實際上是一個bug,Null 實際上是基本型別的值。
typeof null // object
原理:不同的物件在底層都表示為二進位制,在 JavaScript 中二進位制前三位都為 0 的話會被判 斷為 object 型別,null 的二進位制表示是全 0,自然前三位也是 0,所以執行 typeof 時會返回“object”。
根據 JavaScript 對語言型別的分類,很容易知道,並不是 JavaScript 萬物皆物件,或者說任何非基本型別的都是物件型別。
基本型別,引用型別(物件型別)
區別基本型別,物件型別,歸根結底還是得從基本型別,物件型別各自特點出發。
基本型別:包括上述中的六種,基本型別的值是一種簡單的資料段。儲存在棧記憶體中;當複製基本型別的值時,複製它的值(改變其中一個,另一個不受影響),比較時,按其值比較。
引用型別:一種資料結構,是一類物件所具有的屬性和方法;引用型別的值是可能是由多個值構成的物件,儲存在棧記憶體與堆記憶體中;當複製引用型別的值時,複製它的引用(改變其中一個,另一個隨之改變),比較時按其引用比較。
根據基本型別與引用型別各自特點,便容易區分。
能否新增/刪除屬性
// 引用型別 let arr = [] arr.name = 'jk' arr.name // jk複製程式碼
// 基本型別 let str = 'mark' str.name = 'chao' str.name // undefined複製程式碼
複製以後,改變其中一個變數,是否對另一個變數有影響
複製基本型別的值時,會建立一個新值,然後把該值複製到為新變數分配的位置上,此後兩個變數互不影響。
let a = 1 let b = a b = 2 console.log(a) //1複製程式碼
複製前:
複製後:
複製引用型別的值時,同樣也會將儲存在變數中的值複製一份放到為新變數分配的空間中,不同的是,此時這個值,實際上是一個指向堆記憶體中的指標。複製結束後,兩個變數將引用同一個物件,改變其中一個,另一個隨之改變。
let obj1 = { name: 'Mary' } let obj2 = obj1 obj2.name = 'Jack' console.log(obj1.name) // 'Jack'複製程式碼
基本包裝函式
既然基本型別並非物件,也就不具備屬性和方法,那為什麼能使用例如length, charAt
的方法的了?這其中起作用的就是基本包裝函式了。
每當讀取一個基本型別值的時候,後臺就會建立一個對應的基本包裝型別的物件,從而讓我們能夠呼叫一些方法來操作這些資料(null, undefined 沒有對應的建構函式形式)。
一個簡單例子:
let str = 'Jack'
let oStr = str.substring(2)複製程式碼
第二行程式碼,訪問 str 時,訪問過程處於讀取模式,也就是會從記憶體中讀取這個字串的值,在讀取過程中,會進行以下幾步:
- 建立一個 String 型別的一個例項;
- 在例項上呼叫相應的方法。
- 銷燬這個例項。
另一種形式表示:
let str = new String('Jack')
let oStr = str.substring(2)
str = null複製程式碼
基本包裝函式,與引用型別主要區別就是物件的生存期,使用 new 操作符建立的引用型別的例項,在執行流離開當前作用域之前一直都儲存在記憶體中,而自動建立的基本包裝型別的物件,則只存在與一行程式碼的執行瞬間,然後被立即銷燬。這也就是不能給基本型別新增屬性和方法的原因了。
完。