原始值与引用值
ES将数据划分为原始值和引用值。
-
原始值:表示单一的数据类型,保存原始值的变量是按值访问的,实际中是操作存储在内存中的实际值,即数据本身,如123、‘hello’、true等。
ES中有6种原始值:Undefined、Null、Boolean、Number、String和Symbol。 -
引用值:表示由多个值(原始值或其他引用值)构成的对象。
ES不允许直接访问对象的内存空间,因此在实际操作对象时,访问的是对该对象的引用,也就是保存该对象的内存地址。
1.值传递
值传递这个概念指的是赋值的过程,即将值复制给变量的过程。
{
let a = 100
let b = a
b++
console.log(a,b); // 输出100,101
let obj = {value : 100} // 赋值对象的引用给变量,变量保存的是数据的引用
let obj2 = obj
obj2.value = 200
console.log(obj.value,obj2.value); // 输出200,200 修改的是同一个引用
}
原始值与引用值的值传递本质上没有区别,都是将一个变量中保存的值复制给另一个变量。但引用值的值传递是修改的引用,因此上面两个value的值都发生了改变。
2.确定数据的类型
如果想要确定数据的类型,可以使用typeof操作符来判断
{
let str = 'hello';
let boo = true;
let num = 100;
let nul;
let un = null;
let obj = new Object();
let arr = [1,2,3,4,5];
console.log(typeof str); // 输出string
console.log(typeof boo); // 输出boolean
console.log(typeof num); // 输出number
console.log(typeof nul); // 输出undefined
console.log(typeof un); // 输出object
console.log(typeof obj); // 输出object
console.log(typeof arr); // 输出object
}
可以看出引用类型的值都是Object对象,因此可以引申出如果要判断引用值的类型就不能使用typeof,而是采用instanceof操作符,来判断引用值是否为某个构造函数的实例。
{
let obj = new Object();
let arr = [1,2,3,4,5];
console.log(obj instanceof Object); // 输出true
console.log(arr instanceof Array); // 输出true
}
instanceof用来判断是否为某一个构造函数的实例,如果是则返回true
原始值的包装对象
为了方便操作原始值,ES提供了3种特殊的引用类型:Boolean、Number、String。它们的实例(被称为包装对象)包含原始值
{
let str = 'Hello,JavaScript!';
let str2 = str.substr(0,5); // 输出 Hello 字符串方法,用来截取索引从0开始,长度为5的字符。
}
在我们实际使用某个原始值的方法或属性时,其执行过程是先会创建一个包含了原始值包装类型的实例,然后调用实例上的特定方法,最后再销毁该实例。
{
let num = "100";
let number = Number(num);
console.log(number); // 输出 100
console.log(typeof number); // 输出 number
let obj = new Number(num);
console.log(typeof obj); // 输出 object
}
Number()直接调用作为转型函数,把值转为number类型的数据。new Number()则是作为构造函数来调用,创建一个number对象的实例。
关于这三种特殊引用类型的属性和方法,整理在后续的笔记中。
1.包装对象不等于原始值
原始值在根本上与包装实例有很大的差别。
{
let str = 'abc';
let str2 = new String('abc');
console.log(typeof str); // 输出 string
console.log(typeof str2); // 输出 object
console.log(str instanceof String); // 输出 false
console.log(str === str2); // 输出 false
}
原始值与引用值看着虽然相同,但实际使用起来是不一样的数据类型,包装实例是对象,而JavaScript中没有比较对象的方法,只能通过宽松相等( == )和严格相等( === )比较
2.原始值的包装与去包装
在需要对一个原始值增加属性时,首先要对这个原始值进行包装(这个过程也被称为装箱)并且给包装后的对象增加属性,而当需要使用值之前要对它进行去包装(也被称为拆箱)。
{
// 通过调用包装构造函数来对原始值进行包装
new Boolean(true);
new String('abc');
new Number(123);
// 通过调用valueOf()来对原始值进行去包装。所有的对象都有这个方法
let b = new Boolean(true);
let str = new String('abc');
let num = new Number(123);
console.log(b.valueOf()); // 输出 true
console.log(str.valueOf()); // 输出 abc
console.log(num.valueOf()); // 输出 123
}
以上是对原始值与引用值的笔记整理,不足之处欢迎指正!