值类型和引用类型
在JavaScript中,基本数据类型(如字符串型、数字型、布尔型、undefined、null)又称为值类型,复杂数据类型(对象)又称为引用类型。引用类型的特点是,变量中保存的仅仅是一个引用的地址,当对变量进行赋值时,并不是将对象复制了一份,而是将两个变量指向了同一个对象的引用。例如,下列代码中的obj1和obj2指向了同一个对象。
1 // 创建一个对象,并通过变量obj1保存对象的引用
2 var obj1 = { name: '小明', age: 18 };
3 // 此时并没有复制对象,而是obj2和obj1两个变量引用了同一个对象
4 var obj2 = obj1;
5 // 比较两个变量是否引用同一个对象
6 console.log(obj2 === obj1); // 输出结果:true
7 // 通过obj2修改对象的属性
8 obj2.name = '小红';
9 // 通过obj1访问对象的name属性
10 console.log(obj1.name); // 输出结果:小红
上述代码执行后,obj1和obj2两个变量引用了同一个对象,此时,无论是使用obj1操作对象还是使用obj2操作对象,实际操作的都是同一个对象,如图1所示。
图1 引用类型
当obj1和obj2两个变量指向了同一个对象后,如果给其中一个变量(如obj1)重新赋值为其他对象,或者重新赋值为其他值,则obj1将不再引用原来的对象,但obj2仍然在引用原来的对象,示例代码如下。
1 var obj1 = { name: '小明', age: 18 };
2 var obj2 = obj1;
3 // obj1指向了一个新创建的对象
4 obj1 = { name: '小红', age: 17 };
5 // obj2仍然指向原来的对象
6 console.log(obj2.name); // 输出结果:小明
在上述代码中,第1行创建的name为小明的对象,最开始只有obj1引用,在执行第2行代码后,obj1和obj2都引用该对象,执行第4行代码后,只有obj2引用该对象。
当一个对象只被一个变量引用的时候,如果这个变量又被重新赋值,则该对象就会变成没有任何变量引用的情况,这时候就会由JavaScript的垃圾回收机制自动释放。
当引用类型的变量作为函数的参数来传递时,其效果和变量之间的赋值类似。如果在函数的参数中修改对象的属性或方法,则在函数外面通过引用这个对象的变量访问时的结果也是修改后的,示例代码如下。
1 function change(obj) {
2 obj.name = '小红'; // 在函数内修改了对象的属性
3 }
4 var stu = { name: '小明', age: 18 };
5 change(stu);
6 console.log(stu.name); // 输出结果:小红
在上述代码中,当调用change()函数后,在change()函数中修改了obj.name的值。修改后,在函数外面通过stu变量访问到的结果是修改后的值,说明变量stu和参数obj引用的是同一个对象。