第四章 变量-作用域-内存
知识点目录
- 理解基本类型和引用类型的值
- 理解执行环境
- 理解垃圾收集
基本类型和引用类型
基本类型:基本数据类型,包括Undefined、Null、Boolean、Number 和 String
引用类型:数组、对象、函数
两者区别和特点
1. 引用类型值可以动态地添加、改变、删除属性和方法,而基本类型不可以
// 引用类型
var obj = new Object()
obj.name = '木子'
console.log(obj.name) // 木子
// 基本类型
var str = 'hello'
str.age = 12
console.log(str.age) // undefined
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
2. 基本类型复制,两个变量是相互独立的;而引用类型复制,两个变量实际引用的同一个对象
- 基本类型
// 基本类型
var num1 = 4
var num2 = num1
1
2
3
2
3
num1的值和num2的值是相互独立的,两个变量参与任何操作互不影响
- 引用类型
var obj1 = {}
var obj2 = obj1
obj1.name = '木木'
console.log(obj2.name) // 木木
1
2
3
4
2
3
4
引用类型复制实际上复制的是一个指针,指针指向存储在堆中的一个对象,复制后,两个变量实际上将引用同一个对象,因此改变其中一个变量,就会影响另一个变量
3. 不管是基本类型还是引用类型都是按值传递参数的
- 基本类型
function add(num) {
num += 10
return num
}
var count = 20
var result = add(count)
console.log(count) // 20
console.log(result) // 30
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
参数 num 与变量 count 互不相识,它们仅仅是具有相同的值
- 引用类型
function setName(obj) {
obj.name = '木子'
}
var per = new Object()
setName(per)
console.log(per.name) // '木子'
1
2
3
4
5
6
2
3
4
5
6
注意: 看到这个例子,会容易有错误的理解,认为引用类型的参数传递是按引用类型的
再看一个例子
function setName(obj) {
obj.name = '木子'
obj = new Object()
obj.name = '小明'
}
var per = new Object()
setName(per)
console.log(per.name) // '木子'
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
在 setName 函数中,重新定义了一个对象并定义不同的 name 属性值,如果对象per是按引用类型的,那么 per.name 会被赋值新对象的值"小明"
,但是访问 per.name 值时,仍然返回"木子"
说明即使函数内部修改了参数值,但原始的引用没有改变
实际上,当在函数内部重写 obj 时,这个变量引用的就是一个局部对象了。而这个局部对象会在函数执行完毕后立即被销毁。
4. 检测基本类型和引用类型值
我们知道 typeof 可以检测基本类型值(除了null),用 typeof 检测null会返回Object
var a = 'sss'
var b = 3
var c = false
var d
var e = null
console.log(typeof a) // string
console.log(typeof b) // number
console.log(typeof c) // boolean
console.log(typeof d) // undefined
console.log(typeof e) // object
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
ECMAScript 提供了 instanceof 操作符来识别变量是否是引用类型,如果是则返回true
var obj = new Object()
console.log(obj instanceof Object) // true
1
2
2