本博客會講解下面幾個概念
數(shù)據(jù)類型轉(zhuǎn)換
內(nèi)存圖
垃圾回收和內(nèi)存泄漏
淺拷貝與深拷貝
數(shù)據(jù)類型轉(zhuǎn)換
1. 任何類型轉(zhuǎn)String(字符)
-
xxx.toString(x)
注意null
和undefined
類型是不能用此方法將值轉(zhuǎn)為String
的地沮,object
則轉(zhuǎn)成的結(jié)果不能與我們預(yù)期相符
下面是代碼
(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
轉(zhuǎn)為相應(yīng)的字符串,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. 任何類型轉(zhuǎn)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'是你要轉(zhuǎn)換的進制辞居,不寫的話默認為十進制片排。
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. 任何類型轉(zhuǎn)Boolean(布爾)
-
Boolean(x)
用Boolean()函數(shù)轉(zhuǎn)換
-
!!x
在要轉(zhuǎn)換的值前加兩個感嘆號就行
關(guān)于布爾,其他值轉(zhuǎn)換成布爾時只有
5個特殊值
為false
,其他都是ture捅僵,這五個false
值為:0
家卖,NaN
,''
(空字符串)庙楚,null
上荡,undefined
。
4.null和undefined
因為這兩個類型都只有一個值馒闷,所以不需要轉(zhuǎn)換
內(nèi)存圖
要知道對象是由基本類型組成的酪捡,那基本類型又是由什么組成的呢?
比如纳账,我寫了"var a = 1"這行代碼逛薇,計算機到底做了什么,這就需要畫內(nèi)存圖來了解疏虫。
1.假設(shè)你有一個8G的內(nèi)存條
2.操作系統(tǒng)開機即占用來512MB內(nèi)存
3.Chrome 打開即占用 1G 內(nèi)存
4.Chrome 各每個網(wǎng)頁分配一定數(shù)量的內(nèi)存
5.這些內(nèi)存要分給頁面渲染器永罚、網(wǎng)絡(luò)模塊、瀏覽器外殼和 JS 引擎(V8引擎)
6.JS 引擎將內(nèi)存分為代碼區(qū)和數(shù)據(jù)區(qū)
我們只研究數(shù)據(jù)區(qū)
7.數(shù)據(jù)區(qū)分為 Stack(棧內(nèi)存) 和 Heap(堆內(nèi)存)
8.簡單類型的數(shù)據(jù)直接存在 Stack 里
9.復(fù)雜類型的數(shù)據(jù)是把 Heap 地址存在 Stack 里卧秘,而本體數(shù)據(jù)則存在Heap里
遇到問題就畫圖呢袱,不要分析
-
問題1:
var a = 1
var b = a
b = 2
請問 a 顯示是幾?
這時我們就畫一張圖
var a = 1
我們可以看到a先被賦值為1翅敌,然后把1存到Stack內(nèi)存里
var b = a
接著b把a的Stack里的內(nèi)存復(fù)制里一份放在自己里
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其實只是記錄了該對象對應(yīng)的heap地址,并沒有存該對象本身(a引用了該對象)
var b = a
實際上a只是把該對象的地址復(fù)制了一份給b而已恋昼,并沒有新建一個對象
b = {name:'b'}
b被新賦值了一個對象看靠,所以內(nèi)存地址和對象都是新的,和a的對象沒關(guān)系了液肌,所以a.name的值為'a'
-
問題3
var a = {name: 'a'}
var b = a
b.name = 'b'
請問現(xiàn)在 a.name 是多少挟炬?
畫內(nèi)存圖~
var a = {name:'a'}
新建變量a儲存對象{name:'a'}的地址
var b = a
b復(fù)制改變量地址
b.name = 'b'
b把該變量的的name值變成'b'
所以a.name的值就是'b'了
- 問題4
var a = {name: 'a'}
var b = a
b = null
請問現(xiàn)在的a是什么?
內(nèi)存圖內(nèi)存圖
var a = {name:'a'}
新建一個對象嗦哆,把對象的內(nèi)存地址給變量a
var b = a
把a的對象內(nèi)存地址復(fù)制給b
b = null
這里要注意谤祖,null
不是對象,所以b并不會影響a對應(yīng)的該對象老速,而是把自己的內(nèi)存從對象內(nèi)存地址變成null
對應(yīng)的16位二進制碼
上面就是內(nèi)存圖的畫法和介紹粥喜,平時多畫內(nèi)存圖就不會出錯了
垃圾回收和內(nèi)存泄漏
如果一個對象沒有被引用,它就是垃圾橘券,將被回收
這個可以用內(nèi)存圖來理解
-
內(nèi)存回收1
var a = {name:xxx}
var b = {name:yyy}
b = null
當b指向的對象在b變成null后额湘,就沒有被引用來卿吐,所以這個對象就變成來垃圾,瀏覽器會在不確定什么時候把它的內(nèi)存回收掉(視總占內(nèi)存大小和cpu頻率選擇)
-
內(nèi)存回收2
var fn = function(){}
document.body.onclick = fn
fn = null
如上面這個代碼锋华,當瀏覽器把當前標簽頁關(guān)閉時嗡官,document就不存在了,沒有人引用這些對象了毯焕,所以這三個對象都會回收
-
內(nèi)存泄漏
但是IE6的垃圾算法有問題衍腥,它無法將之前三個對象標記為垃圾,所以會一直留著
你只要不關(guān)掉整個瀏覽器纳猫,你的內(nèi)存會會充滿垃圾婆咸,無法重復(fù)利用
這就是內(nèi)存泄漏
淺拷貝與深拷貝
深拷貝
var a = 1
var b = a
b = 2 //這個時候改變 b
a 完全不受 b 的影響
那么我們就說這是一個深復(fù)制(深拷貝)
對于簡單類型的數(shù)據(jù)來說,賦值就是深拷貝续担。
對于復(fù)雜類型的數(shù)據(jù)(對象)來說擅耽,才要區(qū)分淺拷貝和深拷貝活孩。
淺拷貝
var a = {name: 'frank'}
var b = a
b.name = 'b'
a.name === 'b' // true
因為我們對b操作后物遇,a也變了
這就是就是淺拷貝
所謂深拷貝,就是對Heap內(nèi)存進行完全的拷貝憾儒,修改該其值不影響另一個值
var a = {name: 'jiujizi'}
var b = deepClone(a) // deepClone 還不知道怎么實現(xiàn)
b.name = 'b'
a.name === 'a' // true