在Javascript中,变量可分为两种:原始值(基本数据类型)和引用值(复杂数据类型)。
- 原始值就是最简单的数据,比如Undefiend、null、Boolean、Number、String、Symbol(ES6引入),原始值变量是按值访问的。
- 引用值则是由多个值构成的对象。对象保存在内存中,是不能直接访问的,因此不能直接操作对象所在的内存空间。实际上操作的是对象的引用,在内存上的一个地址。
通过变量进行赋值时
- 原始值通过变量进行赋值到另一个变量时,原始值会被复制到新变量的位置,赋值后他们是各自独立的。
- 引用值从一个变量赋值给另一个变量时,实际上是把指向存储在堆内存中的对象的引用(即这个对象的地址),赋值给这个变量。就好像我们寄快递,变量就是快递,值就是地址。可能有多个快递,但是收货点是我们自己的家。这几个快递在内存中是独立存在的,但是投递指向的地址是一样的。
// 复制值
// 原始值
let a = 10;
console.log(a); // 10
let b = a;
a = 20;
console.log(a); // 20
console.log(b); // 10
// 引用值
let obj1 = { value: 1 }; // 实际上obj1存储的是指向{value:1}的地址
console.log(obj1); // { value:1 }
let obj2 = obj1; // 将指向obj1的地址赋值给obj2,让obj2也指向{value:1}
console.log(obj2); // {value:1}
obj1.value = 2;
console.log(obj2); // {value:2}
动态属性
原始值和引用值的定义方式类似,都是创建一个变量,然后赋值。
但是引用值可以随时添加、修改或删除其属性和方法。原始值不能有属性,添加时不会报错,但是访问的时候是undefiend。
注:如果使用new关键字创建,则会创建一个Object实例,但行为类似原始值。但是可以有属性和方法
// 动态属性
let actObj = {
value: 1,
};
actObj.key = "test";
console.log(actObj); // {value:1,key:'test'}
let actValue = 1;
actValue.key = "test";
console.log(actValue.key); // undefined
传递参数
所有函数的参数都是按值传递的,只会被复制到一个局部变量,就是arguments对象中的一个槽位。参数就是一个局部变量,
在引用类型传递参数时,实际上是值在内存中的位置被保存在一个局部变量,就是说本地变量的修改会反映到函数外部。
// 传递参数
// 原始值
let a = 20;
function test(value) {
console.log(value); // 20
value = 10;
}
test(a);
console.log(a); // 20, 内部没有影响外部
// 引用值
let obj = { key: "这是没有修改的值" };
let obj1 = { key: "这是没有修改的值" };
function test1(value) {
console.log(value);
value.key = "这是修改后的值";
}
test1(obj);
console.log(obj); // {key:'这是修改后的值'}
function test2(value) {
console.log(value);
value.key = "这是修改后的值";
value = 123;
console.log(value); // 123
}
test2(obj1);
console.log(obj1); // {key:'这是修改后的值'}
确定类型
typeof用来判断变量是否为字符串、数值、布尔值或undefined的最好方式,但是null和object会被判定为“object”,如果实现内部[[Call]]方法的对象,则会返回‘function’。
instanceof操作符来解决它是什么类型的对象,返回值是布尔值,如果仅测试用原始字面量形式创建的原始值,最终都会返回false,因为原始值不是对象.