定义
在《JavaScript高级程序设计》第三版 4.1.3,讲到传递参数:
ECMAScript中所有函数的参数都是按值传递的。
什么是按值传递呢?
也就是说,把函数外部的值复制给函数内部的参数,就和把值从一个变量复制到另一个变量一样。
按值传递
举个简单的例子:
var value = 1;
function foo(v) { v = 2; console.log(v); //2 } foo(value); console.log(value) // 1
很好理解,当传递 value 到函数 foo 中,相当于拷贝了一份 value,假设拷贝的这份叫 _value,函数中修改的都是 _value 的值,而不会影响原来的 value 值。
引用传递?
举个例子:
var obj = {
value: 1
};
function foo(o) { o.value = 2; console.log(o.value); //2 } foo(obj); console.log(obj.value) // 2
第三种传递方式
不急,让我们再看个例子:
var obj = {
value: 1
};
function foo(o) { o = 2; console.log(o); //2 } foo(obj); console.log(obj.value) // 1
例子一:
var value = 1;
function foo(v) {
v = 2;
console.log(v); //2
}
foo(value);
console.log(value) // 1
内存分布如下:
改变前:
栈内存
堆内存
value
1
v
1
改变后:
栈内存
堆内存
value
1
v
2
例子二:
var obj = {
value: 1
};
function foo(o) {
o.value = 2;
console.log(o.value); //2
}
foo(obj);
console.log(obj.value) // 2
内存分布如下:
改变前:
栈内存
堆内存
obj,o
指针地址
{value: 1}
改变后:
栈内存
堆内存
obj,o
指针地址
{value: 2}
例子三:
var obj = {
value: 1
};
function foo(o) {
o = 2;
console.log(o); //2
}
foo(obj);
console.log(obj.value) // 1
内存分布如下:
改变前:
栈内存
堆内存
obj,o
指针地址
{value: 1}
改变后:
栈内存
堆内存
obj
指针地址
{value: 1}
o
2
关键点:
运算符
=
就是创建或修改变量在内存中的指向.
初始化变量时为创建,重新赋值即为修改.
首先一个非常简单的例子:
var a = {b: 1};// a = {b: 1}
var c = a;// c = {b: 1}
a = 2;// 重新赋值a
console.log(c);// {b: 1}
接着是上一段代码在内存中的分布:
栈
堆
a, c
{b: 1}
然后一步一步执行代码:
- 创建变量a指向
对象{b: 1}
; - 创建变量c指向
对象{b: 1}
; - a重新指向常量区的
2
;
栈
堆
常量区
a
2
c
{b: 1}
所以c从始至终都是指向
对象{b: 1}
.
var value = 1;
function foo(v) {
v = 2;
console.log(v); //2
}
foo(value);
console.log(value) // 1
将案例一等价替换:
var value = 1;
function foo() {
var v = value; // 创建变量v指向value所指向的值
v = 2;// v重新指向另外的值
console.log(v); //2
}
foo(value);
console.log(value) // 1,value从始至终都未改变指向.
案例三也可以这样替换.
接着分析案例二:
修改一下我的第一个例子:
var a = {b: 1};// a = {b: 1}
var c = a;// c = {b: 1}
a.b = 2;// 重新赋值对象a中的属性b
console.log(c);// {b: 2},// c也随着修改,从
在内存中的分布:
栈
堆
常量区
a,c
[[Object]]
b
1
执行完a.b = 2
后:
栈
堆
常量区
a,c
[[Object]]
b
2
那么a,c从始至终都未改变指向,只是b改变了而已
第一张内存分布图将{b: 1}放入堆中,是为了大家更方便抓住重点
所以案例二等量替换为
var obj = {
value: 1
};
function foo() {
var o = obj;
o.value = 2;// 变量value改变了指向,而o并未改变
console.log(o.value); //2
}
foo(obj);
console.log(obj.value) // 2
不管是基本数据类型还是对象类型的,都是拷贝。前者拷贝值,后者拷贝地址值。