ECMAScript
变量可以包含两种不同类型的数据:原始值和引用值。原始值就是简单数据类型,引用值则是由多个值构成的对象
原始值,引用值
原始值包括:Undefined
,Null
,Boolean
,Number
,String
,Symbol
和BigInt (ES2020)
引用值是保存在内存中的对象,即对象保存在堆中
用来保存对象的变量其实只是保存了一个对象的引用,即地址
对于原始值Boolean
,Number
和String
都自带有一个包装对象
let bool1 = true
let bool2 = new Boolean(true)
console.log(bool1 === bool2) //false
console.log(typeof bool1, typeof bool2) //'boolean' 'object' //经过包装对象生成的实例是Object类型
复制值
原始值在复制值时,复制的是副本,而对象类型复制的只是引用,都指向同一个对象
//原始值
let name = 'name'
let another = name
console.log(name) //'name'
another = 'another name'
console.log(name) //'name' //复制后两个变量是独立的
console.log(another) //'another name'
//引用值
let obj1 = new Object()
let obj2 = obj1
console.log(obj1, obj2, obj1 === obj2) //{} {} true
obj2.name = 'obj2 name'
console.log(obj1, obj2, obj1 === obj2) //{name: 'obj2 name'} {name: 'obj2 name'} true //复制后,两个变量指向的仍是同一个对象,即引用相同
传递参数
ECMAScript
中所有函数的参数都是按值传递。如果是原始值,那么就跟原始值变量复制一样,而如果是对象,那么就跟引用值变量复制一样
//原始值传值
function addTen(number) {
number += 10
return number
}
let number = 1
let returnNum = addTen(number)
console.log(number) //1
console.log(returnNum) //11
//引用值传值
function setName(obj) {
obj.name = 'add a name' //实则给局部变量obj指向的对象添加一个属性name并赋值
obj = new Object()//将局部变量obj赋值为两一个对象的引用
obj.name = 'another a name' //给这个对象添加name属性并赋值,但不会影响重新赋值之前的对象
}
let obj = new Object() //obj变量存了一个指向通过new Object()生成的对象的地址,即指针也叫引用
setName(obj) //在这里传递的是引用值,即函数形参存了一个和obj变量一样的引用值,都指向上面通过new Object()创建的对象的地址
console.log(obj.name) //'add a name'
确定类型
通常使用typeof
操作符能判断出字符串、数值、布尔值,undefined
。使用instanceof
可以判断对象变量是什么类型的对象。对于更具体的判断可以使用Object.prototype.toString.call()
进行判断
let str = 'name'
let num = '1111'
let bool = true
let n
let nul = null
let obj = {}
typeof str //string
typeof num //number
typeof bool //boolean
typeof n //undefined
typeof nul //object
typeof obj //object
let arr = new Array()
arr instanceof Object //true //所有引用值都是 Object 的实例,因此通过 instanceof 操作符检测任何引用值和 Object 构造函数都会返回 true
arr instanceof Array //true
arr instanceof String //false