JS里的类型

类型转换

见下图

如何转为 string

就是其他类型变成字符串的一些操作,虽然是用 toString 这个 API, 但是更常用的是与 ‘’ 符号相加以及全局函数 window.String()

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

然而有

1 + '1' // "11"

原因是

(1).toString() + '1'

如何转为 Boolean

其他类型转变成 Boolean 的一些操作,就是调用 Boolean() 或者用 !!

Boolean(类型值)
!! 类型值

注意这里有 5 个 falsy 值,就是转成 Boolean 值的时候为 false 的几个值

  • 0
  • NAN
  • ‘’
  • null
  • undefined

google 搜索 MDN + Falsy,有真相

如何转为 number

以 ‘1’ 转换成 1 为例

  • Number(‘1’) === 1
  • parseInt(‘1’, 10) === 1
  • parseFloat(‘1.23’) === 1.23
  • ‘1’ - 0 === 1
  • +’1’ === 1(取正)

paseInt 这里需要注意的

parseInt('011') // 11
parseInt('011', 10) // 11
parseInt('011', 8) // 9

后面传的参数代表的是进制数

内存图

见下图

以下面这一串代码为例

var a = 1
var b = 2
var o = {
name: 'frank',
age: 18
}
var c = true
o.gender = 'male'

代码在运行之前需要做一次变量提升,为什么需要进行变量提升,因为考虑到对象后面会自己加属性值,而按照图中 stack 栈内存来存储数据的方式,整个栈数据需要进行上移或下移的操作,这样会极大的影响性能,为了解决这个 bug,引入了 heap 堆内存,栈内存中只存放对象的地址,这样只需要取到其地址对应的值就可以了

有关 JS 内存的一些的问题

见如下代码

var a = 1
var b = a
b = 2
a = ? // a = 1

var a = {name: 'a'}
b = a
b = {name: 'b'} // 这里声明了一个匿名对象,这个匿名对象自己也有个地址
a.name = ? // a.name = 'a'

var a = {name: 'a'}
var b = a
b.name = 'b'
a.name = ? // a.name = 'b'

var a = {name: 'a'}
var b = a
b = null
a = ? // a = {name: 'a'}

另起一行

var a = {}
a.self = a
a.self.self.self // 这里被循环指向了

关系见下图

相关面试题

引用类型

var a = {n: 1}
var b = a
a.x = a = {n: 2} // 这里最左边的 a 地址没变,中间 a 地址变了

alert(a.x) // --> undefined // 这里是求变了地址的 a.x
alert(b.x) // ---> [object Object]

为什么会出现上面的情况?原因见内存图

GC 垃圾回收

如果一个对象没有被引用,它就是垃圾,它将会被回收。如下所见一个典型的垃圾回收代码

var a = {name: 'a'}
var b = {name: 'b'}
a = b // 这样原来 a 指向的那片内存就成了垃圾

var fn = function() {}
document.body.onclick = fn
fn = null // fn 不是垃圾回收对象

见下图

那假如把页面关掉,那么 fn 就是垃圾,因为 document 就没有了,其他那些指向都没了。但是 IE6 无法在页面关闭的时候把那些 onclick 标记为垃圾,从而导致内存泄露

所谓浅拷贝和深拷贝

var a = 1
var b = a
b = 2
a = 1

b 变化不影响 a,那么就是深拷贝,一般基本类型的赋值都是深拷贝

var a = {name:'a'}
var b = a
b.name = 'b'
a.name

见下图

以上代码其实就是浅拷贝了