JavaScript的值传递和引用传递
一: JavaScript有5种基本的数据类型:布尔、null、undefined、String和Number。这些基本类型在赋值的时候是通过值传递的方式。
另外一种复杂的数据类型object(Array、Function和Object)它们通过引用来传递。
数据类型 |
转换为true的值 |
转换为false的值 |
Boolean |
true |
false |
String |
任何非空字符串 |
“”(空字符串) |
Number |
任何非0数字 |
0和NaN(not a number) |
Object |
任何对象 |
null |
Undefined |
不适用 |
undefined |
二:引用传递---内存地址不能改变,属性值可以改变
对象是通过引用传递,而不是值传递。也就是说,变量赋值只会将地址(#001)传递过去,一旦地址内容改变则使用这个地址的所有变量的值也会改变
说明:
var a=[1];
var b=a;
变量与地址的对应关系:
变量 |
地址 |
对象 |
a |
#001 |
[1] |
b |
#001 |
栗子1:
Var a=[1,2,3];
Var b=a;
a.push(78);//或者是b改变,b.push(78);,结果一样的
console.log(a);//[1,2,3,78]
console.log(b);//[1,2,3,78]
有个坑:重新赋值==换了一个新的内存地址,则b不改变
Var a =[1,2,3,4]; var b=a; a=[6,7,8,9];console.log(b) //1,2,3,4 只用引用地址里面的值改变了,可以一个一个添加进去
var a =[1,2,3,4]; a=[6,7,8,9];var b=a; console.log(b)//6,7,8,9 引用地址的同时也取了值
引用重新赋值
如果我们将一个已经赋值的变量重新赋值,那么它将包含新的数据或则引用地址
var b = { first: 'fundebug.com'}; b = { second: 'fundebug.cn'}; |
obj从指向第一个对象变为指向第二个对象。
如果一个对象没有被任何变量指向,就如第一个对象(地址为#001
),JavaScript引擎的垃圾回收机制会将该对象销毁并释放内存。
变量 |
地址 |
对象 |
b |
#001 |
{first: ‘fundebug.com’} |
|
#002 |
{second: ‘fundebug.cn’} |
|
|
|
对于引用类型的变量,==
和===
只会判断引用的地址是否相同,而不会判断对象具体里属性以及值是否相同,
如果两个变量指向相同的对象,则返回true
。
如果是不同的对象,及时包含相同的属性和值,也会返回false
。
栗子2:
Var a={name:’lili’};
Var b=a;
Console.log(a===b)//true
栗子3:
Var c=[1,2,3,45];
Var d=[1,2,3,45];
Console.log(c===d)//false
如果想判断两个不同的对象的值是否相同,一个简单的方法就是将它们转换为字符串然后判断。
栗子4:
var cstr = JSON.stringify(c); var dstr = JSON.stringify(d);
console.log(c === d); // true |
纯函数
对于一个函数,给定一个输入,返回一个唯一的输出。除此之外,不会对外部环境产生任何附带影响。我们机会称该函数为纯函数。所有函数内部定义的变量在函数返回之后都被垃圾回收掉。
但是,如果函数的输入是对象(Array, Function, Object),那么传入的是一个引用。对该变量的操作将会影响到原本的对象。
因此,很多数组函数,比如Array.map
和Array.filter
是以纯函数的形式实现。虽然它们的参数是一个数组变量,但是通过深度拷贝并赋值给一个新的变量,然后在新的数组上操作,来防止原始数组被更改。
我们来看一个例子:
栗子6
function changeAgeImpure(person) { person.age = 25; return person; } var alex = { name: 'Alex', age: 30 }; var changedAlex = changeAgeImpure(alex); console.log(alex); // { name: 'Alex', age: 25 } console.log(changedAlex); // { name: 'Alex', age: 25 } |
在非纯函数changeAgeImpure
中,将对象person
的age
更新并返回。原始的alex
对象也被影响,age
更新为25。
让我们来看如何实现一个纯函数:
栗子7
function changeAgePure(person) { var newPersonObj = JSON.parse(JSON.stringify(person)); newPersonObj.age = 25; return newPersonObj; } var alex = { name: 'Alex', age: 30 }; var alexChanged = changeAgePure(alex); console.log(alex); // { name: 'Alex', age: 30 } console.log(alexChanged); // { name: 'Alex', age: 25 } |
我们通过JSON.sringify
将对象变为一个字符串,然后再通过JSON.parse
将字符串变回对象。通过该操作会生成一个新的对象。
栗子8
function changeAgeAndReference(person) {
person.age = 25;//对于personObj1:可以修改引用传递的属性值
person = {// 对于personObj1:不能修改引用传递的内存地址
name: 'John',
age: 50
};
return person;
}
var personObj1 = {
name: 'Alex',
age: 30
};
var personObj2 = changeAgeAndReference(personObj1);
console.log(personObj1); // {name: "Alex", age: 25}
console.log(personObj2); // {name: "John", age: 50}