本博客會講解下面幾個概念
數(shù)據(jù)類型轉換
內存圖
垃圾回收和內存泄漏
淺拷貝與深拷貝
數(shù)據(jù)類型轉換
1. 任何類型轉String(字符)
-
xxx.toString(x)
注意null和undefined類型是不能用此方法將值轉為String的,object則轉成的結果不能與我們預期相符
下面是代碼
(1).toString() // "1"
true.toString() // "true"
null.toString() // Cannot read property 'toString' of null 無法讀取null的'toString'屬性
undefined.toString() // Cannot read property 'toString' of undefined 無法讀取undefined的'toString'屬性
{}.toString() // Unexpcted token 突如其來的標記
({}).toString() "[object Object]"
-
String(x)
這個方法則可以將null和undefined轉為相應的字符串,object還是有之前的問題
下面是代碼
String(1) // "1"
String(true) // "true"
String(null) // "null"
String(undefined) // "undefined"
String({}) // "[object Object]"
-
x+''
利用任何數(shù)值與空字符串相加都會變成字符串,所以可以用下面這個方法
下面是代碼
1+'' // "1"
true+'' // "true"
null+'' // "null"
undefined+'' // "undefined"
var o = {}
o+'' // "[object Object]"
舉個栗子,如果用1+'1',沒辦法去加,由于加號只能加相同類型的東西,所以會把左邊的先.toString,再去加字符串"1"
1+'1' // "11"
2. 任何類型轉number(數(shù)值)
-
Number(x)
下面是代碼
Number('12345') // 12345
Number(null) // 0
Number(undefined) // NaN
Number(true)/Number(false) // 1/0
var a = {}
Number(a) // NaN
-
parseInt(x,10)
'10'是你要轉換的進制,不寫的話默認為十進制。
parseInt()會從頭開始,能判斷多少就多少,不能判斷的則跳過。MDN資料
下面是代碼
parseInt('12345',10) // 12345
parseInt(null,10) // NaN
parseInt(undefined,10) // NaN
parseInt(true,10)/parseInt(false,10) // NaN
var a = {}
parseInt(a,10) // NaN
-
parseFloat(x)
parseFloat() 函數(shù)解析一個字符串參數(shù)并返回一個浮點數(shù)。MDN資料
下面是代碼
parseFloat('12345') // 12345
parseFloat(null) // NaN
parseFloat(undefined) // NaN
parseFloat(true)/parseFloat(false) // NaN
var a = {}
parseFloat(a) // NaN
-
x-0
任何東西減0也會得到你想要的值
下面是代碼
'111'-0 // 111
null-0 // 0
undefined-0 // NaN
true-0/false-0 // 1/0
var a ={}
a-0 // NaN
-
+x
在值前面放個'+'號,能取它原本的值,以數(shù)字的形式展示
下面是代碼
+'111' // 111
+null // 0
+undefined // NaN
+true/+false // 1/0
var a ={}
+a // NaN
3. 任何類型轉Boolean(布爾)
-
Boolean(x)
用Boolean()函數(shù)轉換
-
!!x
在要轉換的值前加兩個感嘆號就行
關于布爾,其他值轉換成布爾時只有
5個特殊值為false,其他都是ture,這五個false值為:0,NaN,''(空字符串),null,undefined。
4.null和undefined
因為這兩個類型都只有一個值,所以不需要轉換
內存圖
要知道對象是由基本類型組成的,那基本類型又是由什么組成的呢?
比如,我寫了"var a = 1"這行代碼,計算機到底做了什么,這就需要畫內存圖來了解。
1.假設你有一個8G的內存條
2.操作系統(tǒng)開機即占用來512MB內存
3.Chrome 打開即占用 1G 內存
4.Chrome 各每個網頁分配一定數(shù)量的內存
5.這些內存要分給頁面渲染器、網絡模塊、瀏覽器外殼和 JS 引擎(V8引擎)
6.JS 引擎將內存分為代碼區(qū)和數(shù)據(jù)區(qū)
我們只研究數(shù)據(jù)區(qū)
7.數(shù)據(jù)區(qū)分為 Stack(棧內存) 和 Heap(堆內存)
8.簡單類型的數(shù)據(jù)直接存在 Stack 里
9.復雜類型的數(shù)據(jù)是把 Heap 地址存在 Stack 里,而本體數(shù)據(jù)則存在Heap里
遇到問題就畫圖,不要分析
-
問題1:
var a = 1
var b = a
b = 2
請問 a 顯示是幾?
這時我們就畫一張圖

var a = 1
我們可以看到a先被賦值為1,然后把1存到Stack內存里
var b = a
接著b把a的Stack里的內存復制里一份放在自己里
b = 2
b的值變成了2,但是并不影響a的值
所以a還是2
-
問題2
var a = {name: 'a'}
var b = a
b = {name: 'b'}
請問現(xiàn)在 a.name 是多少?
我們再畫一張圖

var a = {name:'a'}
新建一個對象,把它賦值給變量a,a其實只是記錄了該對象對應的heap地址,并沒有存該對象本身(a引用了該對象)
var b = a
實際上a只是把該對象的地址復制了一份給b而已,并沒有新建一個對象
b = {name:'b'}
b被新賦值了一個對象,所以內存地址和對象都是新的,和a的對象沒關系了,所以a.name的值為'a'
-
問題3
var a = {name: 'a'}
var b = a
b.name = 'b'
請問現(xiàn)在 a.name 是多少?
畫內存圖~

var a = {name:'a'}
新建變量a儲存對象{name:'a'}的地址
var b = a
b復制改變量地址
b.name = 'b'
b把該變量的的name值變成'b'
所以a.name的值就是'b'了
- 問題4
var a = {name: 'a'}
var b = a
b = null
請問現(xiàn)在的a是什么?
內存圖內存圖

var a = {name:'a'}
新建一個對象,把對象的內存地址給變量a
var b = a
把a的對象內存地址復制給b
b = null
這里要注意,null不是對象,所以b并不會影響a對應的該對象,而是把自己的內存從對象內存地址變成null對應的16位二進制碼
上面就是內存圖的畫法和介紹,平時多畫內存圖就不會出錯了
垃圾回收和內存泄漏
如果一個對象沒有被引用,它就是垃圾,將被回收
這個可以用內存圖來理解
-
內存回收1
var a = {name:xxx}
var b = {name:yyy}
b = null

當b指向的對象在b變成null后,就沒有被引用來,所以這個對象就變成來垃圾,瀏覽器會在不確定什么時候把它的內存回收掉(視總占內存大小和cpu頻率選擇)
-
內存回收2
var fn = function(){}
document.body.onclick = fn
fn = null

如上面這個代碼,當瀏覽器把當前標簽頁關閉時,document就不存在了,沒有人引用這些對象了,所以這三個對象都會回收
-
內存泄漏
但是IE6的垃圾算法有問題,它無法將之前三個對象標記為垃圾,所以會一直留著
你只要不關掉整個瀏覽器,你的內存會會充滿垃圾,無法重復利用
這就是內存泄漏
淺拷貝與深拷貝
深拷貝
var a = 1
var b = a
b = 2 //這個時候改變 b
a 完全不受 b 的影響
那么我們就說這是一個深復制(深拷貝)
對于簡單類型的數(shù)據(jù)來說,賦值就是深拷貝。
對于復雜類型的數(shù)據(jù)(對象)來說,才要區(qū)分淺拷貝和深拷貝。
淺拷貝
var a = {name: 'frank'}
var b = a
b.name = 'b'
a.name === 'b' // true
因為我們對b操作后,a也變了
這就是就是淺拷貝
所謂深拷貝,就是對Heap內存進行完全的拷貝,修改該其值不影響另一個值
var a = {name: 'jiujizi'}
var b = deepClone(a) // deepClone 還不知道怎么實現(xiàn)
b.name = 'b'
a.name === 'a' // true