js类型转换,内存图,数据的引用,垃圾回收,深拷贝vs浅拷贝

js类型转换的方法
6个falsy值
内存图
数据的引用
垃圾回收
深拷贝vs浅拷贝

转成字符串

String(x)

String(x)是一个window的全局方法

x.toString()

null和undefined没有.toString()方法

1
2
3
4
5
6
7
1.toString() //报错
解析器不知道第一个点应该理解成小数点,还是应该理解成调用方法,因此报错
1..toString() // '1' 第一个点表示小数点,第二个点表示调用方法
1.0.toString() // '1'
1 .toString() // '1'
(1).toString() // '1'

x + ‘’ 与空字符串相加

这种方法比较简便,推荐用这种方法转成字符串

转成布尔值

Boolean(x)

注意!空对象是true

!!x

转成数字

Number(x)

1
2
3
4
5
6
Number('3') //3 变成数字
Number('sss') //NaN NaN也是数字类型
Number(true) //1
Number(false) //0
Number(null) //0
Number(undefined) //NaN

parseInt(x)

parseInt('123')

面试题

1
2
3
4
5
6
7
var a = 011; // a=9 js看到0开头默认转成8进制
parseInt('011') // 11 【默认转成10进制】
parseInt('011',8) // 9
parseInt('s') // NaN
parseInt('1s') // 1

parseFloat(x)

parseFloat(3.14)

x - 0 推荐这种

1
2
'123'-0 // 123
'3.14'-0 // 3.14

+x 取正

1
2
+ '-1' // -1
+ '3.14' // 3.14

6个falsy值

0、NaN、空字符串、false、null、undefined

所有对象的falsy值都是true

1
2
3
4
5
var a = false;
var b = new Boolean(false);
if(a){console.log(1)}
if(b){console.log(2)}
结果是2,因为b是个对象

!注意:{}是true值,因为{}是空对象,所有对象都是true!!

内存图

  • JS 引擎将内存分为代码区和数据区

我们只研究数据区

  • 数据区又分为 Stack区(栈内存) 和 Heap区(堆内存)
  • 简单类型的数据直接存在 Stack栈内存 里
  • 复杂类型(object)把地址存到 Stack栈内存 区,把地址对应的数据存到 Heap堆内存 区

o2 = o;并不是修改了o2在Heap的数据,而是将o2的地址修改成o的地址,因此2访问o对应的数据

面试题-对象的引用

1
2
3
4
5
6
7
8
默认已经变量提升
var a = {name: 'a'} //先在Heap区生成数据,然后在Stack区生成a的Address指向对应的数据
var b = a // 将a的地址赋给b,而不是将a的数据赋值给b
b = {name: 'b'} //在Heap区生成新的数据,然后生成b的地址指向对应的数据
请问现在 a.name 是多少? // 'a' a的地址没变,仍旧指向a的数据
b = {name:'b'}并不会修改Heap区的数据,而是声明一个新的数据,
然后Stack区的地址修改为新声明的数据对应的地址


1
2
3
4
5
默认已经变量提升
var a = {name: 'a'} // 先在Heap区生成数据,然后在Stack区生成a的Address指向对应的数据
var b = a // 将a的地址赋给b,此时b指向a的地址对应的数据
b.name = 'b' // 修改a的地址对应的数据
请问现在 a.name 是多少? // 'b'


1
2
3
4
var a = {name: 'a'}
var b = a
b = null // null是简单类型,所以直接将b的STack区修改为null
请问现在 a 是什么? // {name: 'a'}


1
2
3
4
5
6
7
var a = {n:1}; // heap区生成数据34,a生成地址34指向数据34
var b = a; // b的地址也是34
a.x = a = {n:2}; //此时最前面a.x是地址34的x
// a.x等于地址a,即 34里的x = 新地址54【因为后面a在heap区生成了数据54{n:2}】
alert(a.x);// --> undefined 这里的a已经变成地址54了,54里的x是undefined
alert(b.x);// --> [object Object] 由于b指向34,而34里的x = 新地址54

面试题-垃圾回收

如果一个对象没有被引用(就是说没有地址指向它),它就是垃圾,将会被回收


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
var fn = function (){};
document.body.onclick = fn;
fn = null;
请问fn是垃圾吗?
不是。
一开始fn的Stack区是地址110,110指向数据fn
document是个复杂类型,所以Stack区存的地址222
数据222里的body也是个复杂类型,所以body存的是地址333
333里的onclick指向一开始声明的fn
fn=nullnull是简单类型,因此fn的Stack区更改为null
虽然fn=null,但是fn被onclick引用,而onclick被body引用,body被document引用
因此fn不是垃圾
document.body.onclick = fn;
此时fn是垃圾,因为没有东西引用它

浅拷贝vs深拷贝

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
var a = 1;
var b = a;
b = 2;//这个时候改变b
console.log(a);// 1 【a 完全不受 b 的影响】
把a赋值给b,当b改变时,a依然不变,这就是深拷贝
对于简单类型的数据来说,赋值就是深拷贝。
对于复杂类型的数据(对象)来说,才要区分浅拷贝和深拷贝。
----------
对象的浅拷贝:
var a = {name:'stage'}; //复杂类型
var b = a; // b的地址就是a的地址,因此指向a的数据
b.name = 'xxx'; //修改a的地址对应的数据
console.log(a.name) // 'xxx'
把a赋值给b(复杂类型的赋值只是将Stack区的地址进行了拷贝),当b改变时,a也改变,这就是浅拷贝
对象的深拷贝:
var a = {name: 'frank'}
var b = deepClone(a) // deepClone 还不知道怎么实现
b.name = 'b'
a.name === 'a' // true
对象的深拷贝就是对 Heap 区进行完全的拷贝。
-------------本文结束感谢您的阅读-------------