第四章 变量-作用域-内存

基本类型和引用类型

基本类型:基本数据类型,包括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. 基本类型复制,两个变量是相互独立的;而引用类型复制,两个变量实际引用的同一个对象

  • 基本类型
// 基本类型
var num1 = 4
var num2 = num1
1
2
3

num1的值和num2的值是相互独立的,两个变量参与任何操作互不影响

An image

  • 引用类型
var obj1 = {}
var obj2 = obj1
obj1.name = '木木'
console.log(obj2.name) // 木木
1
2
3
4

引用类型复制实际上复制的是一个指针,指针指向存储在堆中的一个对象,复制后,两个变量实际上将引用同一个对象,因此改变其中一个变量,就会影响另一个变量

An image

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

参数 num 与变量 count 互不相识,它们仅仅是具有相同的值

  • 引用类型
function setName(obj) {
  obj.name = '木子'
}
var per = new Object()
setName(per)
console.log(per.name) // '木子'
1
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

在 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

ECMAScript 提供了 instanceof 操作符来识别变量是否是引用类型,如果是则返回true

var obj = new Object()
console.log(obj instanceof Object) // true
1
2

执行环境和作用域