JS数据类型转换

2019-02-13  本文已影响33人  酒极子

本博客会讲解下面几个概念

数据类型转换
内存图
垃圾回收和内存泄漏
浅拷贝与深拷贝

数据类型转换

1. 任何类型转String(字符)

注意nullundefined类型是不能用此方法将值转为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]"

这个方法则可以将nullundefined转为相应的字符串,object还是有之前的问题

下面是代码

String(1)  //  "1"
String(true)  //  "true"
String(null)  //  "null"
String(undefined)  //  "undefined"
String({})  //  "[object Object]"

利用任何数值与空字符串相加都会变成字符串,所以可以用下面这个方法

下面是代码

1+''  //  "1"
true+''  //  "true"
null+''  //  "null"
undefined+''  //  "undefined"
var o = {}
o+''  //  "[object Object]"

举个栗子,如果用1+'1',没办法去加,由于加号只能加相同类型的东西,所以会把左边的先.toString,再去加字符串"1"

1+'1'  //  "11"

2. 任何类型转number(数值)

下面是代码

Number('12345')  //  12345
Number(null)  //  0  
Number(undefined)  //  NaN
Number(true)/Number(false)  //  1/0
var a = {}
Number(a)  //  NaN

'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() 函数解析一个字符串参数并返回一个浮点数。MDN资料

下面是代码

parseFloat('12345')  //  12345
parseFloat(null)  //  NaN
parseFloat(undefined)  //  NaN
parseFloat(true)/parseFloat(false)  //  NaN
var a = {}
parseFloat(a)  //  NaN

任何东西减0也会得到你想要的值

下面是代码

'111'-0  //  111
null-0  //  0
undefined-0  //  NaN
true-0/false-0  //  1/0
var a ={}
a-0  //  NaN

在值前面放个'+'号,能取它原本的值,以数字的形式展示

下面是代码

+'111'  //  111
+null  //  0
+undefined  //  NaN
+true/+false  //  1/0
var a ={}
+a  //  NaN

3. 任何类型转Boolean(布尔)

用Boolean()函数转换

在要转换的值前加两个感叹号就行

关于布尔,其他值转换成布尔时只有5个特殊值false,其他都是ture,这五个false值为:0NaN''(空字符串),nullundefined

4.null和undefined

因为这两个类型都只有一个值,所以不需要转换

内存图

要知道对象是由基本类型组成的,那基本类型又是由什么组成的呢?
比如,我写了"var a = 1"这行代码,计算机到底做了什么,这就需要画内存图来了解。

1.假设你有一个8G的内存条
2.操作系统开机即占用来512MB内存
3.Chrome 打开即占用 1G 内存
4.Chrome 各每个网页分配一定数量的内存
5.这些内存要分给页面渲染器、网络模块、浏览器外壳和 JS 引擎(V8引擎)
6.JS 引擎将内存分为代码区和数据区

我们只研究数据区
7.数据区分为 Stack(栈内存) 和 Heap(堆内存)
8.简单类型的数据直接存在 Stack 里
9.复杂类型的数据是把 Heap 地址存在 Stack 里,而本体数据则存在Heap里

遇到问题就画图,不要分析

var a = 1
var b = a
b = 2
请问 a 显示是几?

这时我们就画一张图


题1内存图
var a = 1

我们可以看到a先被赋值为1,然后把1存到Stack内存里

var b = a

接着b把a的Stack里的内存复制里一份放在自己里

b = 2

b的值变成了2,但是并不影响a的值
所以a还是2

var a = {name: 'a'}
var b = a
b = {name: 'b'}
请问现在 a.name 是多少?

我们再画一张图


题2内存图
var a = {name:'a'}

新建一个对象,把它赋值给变量a,a其实只是记录了该对象对应的heap地址,并没有存该对象本身(a引用了该对象)

var b = a

实际上a只是把该对象的地址复制了一份给b而已,并没有新建一个对象

b = {name:'b'}

b被新赋值了一个对象,所以内存地址和对象都是新的,和a的对象没关系了,所以a.name的值为'a'

var a = {name: 'a'}
var b = a
b.name = 'b'
请问现在 a.name 是多少?

画内存图~


题3内存图
var a = {name:'a'}

新建变量a储存对象{name:'a'}的地址

var b = a

b复制改变量地址

b.name = 'b'

b把该变量的的name值变成'b'
所以a.name的值就是'b'了

var a = {name: 'a'}
var b = a
b = null
请问现在的a是什么?

内存图内存图


题4内存图
var a = {name:'a'}

新建一个对象,把对象的内存地址给变量a

var b = a

把a的对象内存地址复制给b

b = null

这里要注意,null不是对象,所以b并不会影响a对应的该对象,而是把自己的内存从对象内存地址变成null对应的16位二进制码

上面就是内存图的画法和介绍,平时多画内存图就不会出错了

垃圾回收和内存泄漏

如果一个对象没有被引用,它就是垃圾,将被回收

这个可以用内存图来理解

var a = {name:xxx}
var b = {name:yyy}
b = null
垃圾回收1

当b指向的对象在b变成null后,就没有被引用来,所以这个对象就变成来垃圾,浏览器会在不确定什么时候把它的内存回收掉(视总占内存大小和cpu频率选择)

var fn = function(){}
document.body.onclick = fn
fn = null
垃圾回收2

如上面这个代码,当浏览器把当前标签页关闭时,document就不存在了,没有人引用这些对象了,所以这三个对象都会回收

但是IE6的垃圾算法有问题,它无法将之前三个对象标记为垃圾,所以会一直留着

你只要不关掉整个浏览器,你的内存会会充满垃圾,无法重复利用

这就是内存泄漏

浅拷贝与深拷贝

深拷贝

var a = 1
var b = a
b = 2 //这个时候改变 b
a 完全不受 b 的影响
那么我们就说这是一个深复制(深拷贝)

对于简单类型的数据来说,赋值就是深拷贝。

对于复杂类型的数据(对象)来说,才要区分浅拷贝和深拷贝。

浅拷贝

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 还不知道怎么实现
b.name = 'b'
a.name === 'a' // true
上一篇 下一篇

猜你喜欢

热点阅读