常见数据类型的转换
除了 Null 和 Undefined 类型,其他数据类型都可以使用
toString()
方法转换为字符串类型,Object 类型虽然有这个方法,但是不一定得到预期的结果(可以使用JSON.stringify()
方法);比toString()
方法更简单的就是将要转换的数据拼接一个空字符串,这个方法更简略也更强大,它实际是使用了隐式类型转换,通过全局方法String()
将数据转换类型。使用全局方法
Boolean()
可以将所有数据类型转换为布尔值;简便方法可以在要转换的数据前,使用两个取反操作符!!
。转换数字类型的方法有
Number()
、parseInt()
和parseFloat()
方法;简便方法可以直接在要转换的数据前加正数符号+
;或者使用数据减 0 的操作,例如'3.14' - 0
,字符串 3.14 就会被转为数字 3.14,这种比较常用。
内存中数据存储方式
编译器会将分配到的内存分为代码区和数据区。
数据区分为 Stack(栈内存) 和 Heap(堆内存)。
堆比栈大,栈比堆快。
JavaScript 代码在编译起始,会先将声明的变量提到最前面。
基本数据类型都保存在栈内存,复杂数据类型都保存在堆内存。
当把一个基本数据类型赋值给一个变量时,变量中存储的就是这个数据本身;当把这个变量赋值给另外一个变量时,相当于将它保存的数据本身,复制一个拷贝,再赋值给新变量,之后,两个变量各拥有一份相互独立的数据。
当把一个复杂数据类型赋值给一个变量时,变量中存储的是这个数据在堆内存中的地址,这种关系称为“引用”;当把这个变量赋值给另外一个变量时,相当于把保存的引用地址,复制一个拷贝,再赋值给新变量,之后,两个变量引用的是同一个数据,相当于两个人各拥有一张代表同一个数据的“名片”。
循环引用
对象自身循环引用可以实现,但是不能在声明对象的同时将其自身保存在内,因为编译的顺序是先根据赋值操作符也就是 =
号的右边的数据大小来开辟内存空间,然后再将存好的数据的地址,存入变量;如果要完成自身的循环引用,需要在对象声明并赋值完成后,再将其自身引用通过添加属性的方式保存到自身当中;循环引用可能会造成内存泄露。
试题解析
1 | var a = {n: 1}; |
上面的题中,第三行的关键点在于确定当时的
a
变量是哪一个;编译器是从上到下依次执行,但是各种操作符除了有优先级之分,还有从右往左和从左往右两种关联性,而属性访问操作符优先级比赋值操作符的优先级要高,所以先确定了
a.x
的a
引用的依然是{n: 1}
这个数据,并在这个数据中添加了一个属性x
,此时x
只是声明后未定义等待赋值的状态,就是说源数据成为了{n: 1, x: undefined}
;然后赋值运算符从右往左执行,先将
a
变量中的数据,赋值为了{n: 2}
的地址,再将这个地址,赋值给了{n: 1, x: undefined}
这个对象中的x
属性,此时数据成为了{n: 1, x: {n: 2}}
;第四行访问
a.x
,此时的a
引用的数据已经是{n: 2}
,里面并没有x
这个属性,故打印出的结果为undefined
;第五行访问
b.x
,此时的b
引用的数据依然是原来包含n: 1
键值的那个数据,而此时这个数据已经有了x
这个属性,并且值为另一个对象引用地址,这个地址对应的数据是{n: 2}
,将其隐性地使用toString()
方法转换为字符串后,打印出的结果便是[object Object]
。
垃圾回收
如果一个对象没有被引用,它就是垃圾数据,将被垃圾回收器清理掉。
垃圾回收器会在页面运行时,按照浏览器设定好的机制循环作业。
深拷贝与浅拷贝
拷贝即复制,复制后的数据与原数据,完全独立且互不影响,就称为“深拷贝”;基本数据类型之间的复制,都是深拷贝。
其实基本数据类型之间的复制谈不上什么”深浅“,深拷贝与浅拷贝主要是对于对象数据之间的复制而言的。
如果将一个对象赋值给一个变量,实际是将这个对象的引用地址保存在里变量当中,那么当复制这个变量到另一个变量时,只是把这个引用地址,存到了新的变量中;当通过新的变量改变对象的属性后,访问原先的变量也能发现对象的属性变化;这种程度的复制,就是“浅拷贝”。
课后拾遗
JavaScript 语言规定,对象的键名一律为字符串,所以,数组的键名其实也是字符串。之所以可以用数值读取,是因为非字符串的键名会被转为字符串。
数组的某个元素为空元素(即两个逗号之间没有任何值)时,便称为这个数组存在空位;空位不影响数组的长度;如果读取空位,会返回
undefined
,但是把一个元素赋值为undefined
后,这个元素不属于空位;如果使用delete
操作符删除某个元素,那么这个元素对应的位置便成为了空位;使用for...in
语句、数组的forEach()
方法以及对象的keys()
方法遍历数组时, 空位都会被跳过。