值类型与引用类型
typeof 识别出来的类型中,只有 object 和 function 是引用类型,其他都是值类型string、number、boolean、undefined、null、symbol。注意:Symbol 也是值类型,实例的唯一标识。
javascript对值和引用的赋值/传递在语法上没有区别,完全根据值的类型来决定。
下面来看一个例子:
var a = 2;
var b = a; // b是a的值的一个复本
b++;
console.log(a); // 2
console.log(b); // 3
var c = [1,2,3];
var d = c; //d是[1,2,3]的一个引用
d.push(4);
console.log(c); // [1,2,3,4]
console.log(d); // [1,2,3,4]
上例中a、b都是值类型,b更改时,a的值保持不变。
c和d都是引用类型,分别指向同一个复合值[1,2,3]的两个不同引用,指向同一个内存地址。请注意,c和d仅仅是执指向值[1,2,3],并非持有。所以它们更改同一个值(调用.push(4)),它们都指向更改后的新值[1,2,3,4]。
由于引用指向的是值本身而非变量,所以一个引用无法更改另外一个引用的指向。
var a = [1,2,3]
var b = a;
console.log(a); // [1,2,3]
console.log(b); // [1,2,3]
// 然后
b = [4,5,6];
console.log(a); // [1,2,3]
console.log(b); // [4,5,6]
b = [4,5,6]并不影响a指向值[1,2,3],除非b不是指向数组的引用,而是指向a的指针,但在javascript中不存在这种情况。
引用类型经常会在代码中按照下面的写法使用,容易不知不觉中造成错误
var obj = {
a:1,
b:[1,2,3]
}
var a = obj.a;
var b = obj.b;
a = 2;
b.push(4);
console.log(obj); // { a:1, b:[1,2,3,4] }
console.log(a,b); // 2, [1, 2, 3, 4]
函数参数指向的值
函数参数经常让人产生这样的困惑:
function foo(x) {
x.push(4);
console.log(x); // [1,2,3,4]
x = [4,5,6];
x.push(7)
console.log(x); // [4,5,6,7]
}
var a = [1,2,3];
foo(a);
console.log(a); // 是[1,2,3,4],不是[4,5,6,7]
我们向函数传递a的时候,实际是将引用a的一个复本赋值给x,而a仍然指向[1,2,3]。在函数中我们通过引用x来更改数组的值(.push(4)之后变成[1,2,3,4])。但x = [4,5,6]并不影响a的指向,所以a仍然指向[1,2,3,4]。
我们不能通过引用x来更改引用a的指向,只能更改a和x共同指向的值。 如果要将a的值变为[4,5,6,7],必须更改x指向的数组,而不是为x赋值一个新的数组。
function foo(x) {
x.push(4);
console.log(x); // [1,2,3,4]
x.length = 0; // 清空数组
x.push(4,5,6,7);
console.log(x); // [4,5,6,7]
}
var a = [1,2,3];
foo(a);
console.log(a); // 是[1,2,3,4],不是[4,5,6,7]
从上例子可以看出, x.length = 0和x.push(4,5,6,7)并没有创建一个新的数组,而是更改了当前的数组。于是a的指向变成了[4,5,6,7]。
如果要将基本类型的值传递到函数内并进行更改,就需要将该值封装到一个复合值(对象、数组等)中,然后通过引用复制的方式传递。
function foo(x) {
x.a = 42;
}
var obj= {
a:2
};
foo(obj);
console.log(obj.a); // 42
来源声明:用于记录学习心得整理总结,内容非原创。