盒子
盒子
文章目录
  1. 其他数据类型转string
  2. 其它数据类型转number
  3. 其它数据类型转成boolean
  4. 四个经典的内存题
  5. 一个很贱的面试题
  6. IE6 的关于垃圾回收机制的一个BUG
  7. 由以上几个题引出深拷贝和浅拷贝 的问题
  8. typeof运算符的坑
  9. 一个小技巧

深挖JavaScript第二集

JS一定要抠细节,逻辑性。我们这次探讨 内存 的问题、一个IE的BUG以及深拷贝和浅拷贝,和typeof运算符的小技巧

在第一集里面知道了7个基本的数据类型
number string boolean symbol null underdefined object
那么这七个数据类型如何转换呢

其他数据类型转string

  • String()函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
String(0)
"0"
String(true)
"true"
String(false)
"false"
String(null)
"null"
String(undefined)
"undefined"
String({})
"[object Object]"
String({name: 9})
"[object Object]"
  • toString()属性
    注意null和undefined只是两个值,没有toString()属性
1
2
3
4
5
6
7
8
null.toString()
VM371:1 Uncaught TypeError: Cannot read property 'toString' of null
at <anonymous>:1:6
(anonymous) @ VM371:1
undefined.toString()
VM400:1 Uncaught TypeError: Cannot read property 'toString' of undefined
at <anonymous>:1:11
(anonymous) @ VM400:1

还有一个要注意的

1
2
3
4
{}.toString()
VM91:1 Uncaught SyntaxError: Unexpected token .
({}).toString()
"[object Object]"

其他的都可以

1
2
3
4
5
6
7
8
9
var a = 8;
a.toString()
"8"
var a = true
a.toString()
"true"
var a = {}
a.toString()
"[object Object]"

  • 最常见的方法 ‘ ‘+
    无敌的方法
1
2
3
4
5
6
7
8
'' +1
"1"
''+ true
"true"
''+ null
"null"
''+ undefined
"undefined"

其它数据类型转number

  • Number()函数
1
2
3
4
5
6
7
8
9
10
11
12
Number('fff')
NaN
Number('30')
30
Number(null) //注意是0
0
Number(undefined) //注意是NaN
NaN
Number(true)
1
Number(false)
0
  • parseInt()和parseFloat()属性
    parseInt()有个大坑,是从左边第一个字符开始看,不是数字,就停下了,而不是我理解 的有几个数字就打印几个数字
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
parseInt('122') //默认是十进制
122
parseInt('011')
11
parseInt('011', 2) //规定是二进制
3
parseInt('123', 10)
123
parseInt('011', 8) //规定是八进制
9
parseInt('A09') //发现第一个字符就不是数字,不往后面判断了
NaN
parseInt('09A12')
9
parseFloat('11.4')
11.4
  • 没见过的操作 其他数据类型-0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
null-0
0
undefined-0
NaN
'91' - 0
91
'91.09' - 0
91.09
'str' - 0
NaN
var a = {}
a-0
NaN
var a = '123'
a-0
123
  • 又是一个没见过的操作 + ''
1
2
3
4
5
6
7
8
9
10
11
12
+'124'
124
+'12.4'
12.4
+false
0
+true
1
+null
0
+undefined
NaN

其它数据类型转成boolean

注意5个特殊的falsey值,当然了false必然也是falsey值


0
NaN
‘ ‘ 这是空字符串,啥也没有,空格也没有
null
undefined


除了以上6个falsey值,其他的都是true

  • Boolean()函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
Boolean('')
false
Boolean(' ')
true
Boolean(0)
false
Boolean(NaN)
false
Boolean(null)
false
Boolean(undefined)
false
Boolean([])
true
Boolean({})
true
Boolean(9)
true
Boolean('pp')
true
  • !!的操作
    怎么理解呢,一个!是取反的操作,再加一个就是双重取反,就是我们想要的结果了
1
2
3
4
!0
true
!1
false
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
!!0
false
!!NaN
false
!!''
false
!!null
false
!!undefined
false
!!1
true
!!'pp'
true
!![]
true
!!{}
true

四个经典的内存题

  • 粗糙的内存图的引入
    var a = 1 和var a = new Number(1)分别发生了什么
    简单数据类型存在stack中,存储位置是连续的,像弹匣一样,与数据结构中的栈一样,先进后出(FILO),而复杂数据类型存储在heap中,存储位置不连续,与数据结构中的堆一样,是树状的发散结构,这一点超级重要啊。时时刻刻要记着数据结构啊。

  • 第一个题 简单数据类型的判断 a=?

    1
    2
    3
    4
    5
    6
    var a = 1
    b = a
    b = 2

    a
    1

答案是a=1
第一题.png

  • 第二个题 复杂数据类型 的判断 a =?
    1
    2
    3
    4
    5
    6
    var a = {name: 'wushao'}
    b =a
    b={name: 'shao'}

    a
    {name: "wushao"}

答案是a={name: ‘wushao’},结果不变
第二题.png

  • 第三个题 复杂数据类型 的判断 a.name=?
1
2
3
4
5
6
var a = {name: 'wushao'}
b =a
b.name = 'qwert'

a.name
"qwert"

答案是a.name = ‘qwert’,已经被b.name改变了
第三题.png

  • 第四个题 复杂数据类型 的判断 a=?
1
2
3
4
5
6
var a = {name: 'a'}
var b = a
b = null

a
{name: "a"}

答案是 a = {name: “a”} 不受b的影响
第四题.png

如图所示

一个很贱的面试题

1
2
3
4
5
6
var a = {n: 1}
var b = a
a.x = a = {n: 2}

alert(a.x) //是啥呢 undefined
alert(b.x) //是啥呢 [object Object]

面试题.png

大坑之处在于那个a.x一开始浏览器先从左边看的

IE6 的关于垃圾回收机制的一个BUG

有以下情形

1
2
3
4
var fn = function( ){ }
document.body.onclick = fn
fn = null
问你 function(){}是不是垃圾
  • 第一种情况,你没有关闭这个tab页
    那么function不是垃圾
    是否是一个垃圾.png
  • 第二种情况,我关闭了这个tab页,那么function就是垃圾了
    关闭网页后就是一个垃圾了.png

IE6的BUG在于,你关闭了网页,但是蓝色圆里面的他不认为是垃圾,除非你关闭浏览器。所以你要在网页关闭的时候手动加上一个

1
2
3
4
//onunload不加载,就是关闭了嘛
window.onunload = function(){
document.body.onclick = null; //所有的都要有
}

由以上几个题引出深拷贝和浅拷贝 的问题

深拷贝是你改变了,原来的不受改变的影响,而浅拷贝会改变原来的属性。
对于简单类型的数据来说,赋值就是深拷贝。
对于复杂类型的数据(对象)来说,才要区分浅拷贝和深拷贝。
深拷贝.png

右边蓝色框才是一个完整的复制

typeof运算符的坑

JavaScript有三种方法,可以确定一个值到底是什么类型。
typeof 运算符
instanceof 运算符
Object.prototype.toString方法

typeof运算符可以判断你要的值得数据类型,有如下结果
先看大坑

1
2
3
4
5
6
7
typeof null
"object"
typeof Function
"function"
function f(){}
typeof f
"function"

函数竟然是function类型的数据,坑爹啊。
null竟然是object,尼玛,吓坏了,一查原来是历史遗留问题。

1995年JavaScript语言的第一版,所有值都设计成32位,其中最低的3位用来表述数据类型,object对应的值是000。当时,只设计了五种数据类型(对象、整数、浮点数、字符串和布尔值),完全没考虑null,只把它当作object的一种特殊值,32位全部为0。这是typeof null返回object的根本原因。
为了兼容以前的代码,后来就没法修改了。这并不是说null就属于对象,本质上null是一个类似于undefined的特殊值。

你只需要记住,null不是对象 !null不是对象! null不是对象!就是一个值null。
其他的类型是符合预期的

1
2
3
4
5
6
7
8
9
10
typeof 123
"number"
typeof '123'
"string"
typeof true
"boolean"
typeof []
"object"
typeof {}
"object"

一个小技巧

1
2
3
4
typeof undefined
"undefined"
typeof a
"undefined"

上面的a未声明,直接使用会报错

1
2
3
a
VM412:1 Uncaught ReferenceError: a is not defined
at <anonymous>:1:1

但是用了typeof就可以啦
可以用来判断某个变量是否声明了

1
2
3
if (typeof v === "undefined") {
// ...
}
  • 第二个小技巧
    既然typeof对数组(array)和对象(object)的显示结果都是object,那么怎么区分它们呢?instanceof运算符可以做到。
1
2
3
4
5
var o = {};
var a = [];

o instanceof Array // false
a instanceof Array // true