mirror of
https://github.com/pengzhanbo/vuepress-theme-plume.git
synced 2026-04-23 10:58:13 +08:00
109 lines
3.5 KiB
Markdown
109 lines
3.5 KiB
Markdown
---
|
||
title: JavaScript进阶(五)— 函数参数按值传递
|
||
createTime: 2020/02/12 11:27:54
|
||
author: pengzhanbo
|
||
permalink: /article/m4a92nl5/
|
||
---
|
||
|
||
我们知道,在 `ECMAScrip` 中, 函数的参数是 **按值传递** 的。
|
||
|
||
那么怎么理解 **按值传递** ?
|
||
|
||
简单来说, **把函数外部的值复制给函数内部的参数**,即 **把值从一个变量复制到另一个变量**。
|
||
|
||
那么也就是说,在函数内部,修改函数参数的值,不会改变外部变量的值。
|
||
|
||
我们来看一个例子:2
|
||
|
||
**示例1**
|
||
```js
|
||
|
||
var a = 1
|
||
function foo(arg) {
|
||
arg = 2
|
||
console.log(arg)
|
||
}
|
||
foo(a) // 2
|
||
console.log(a) // 1
|
||
```
|
||
|
||
可以看出,外部变量`a`作为 函数 `foo` 的执行时参数值, 在函数内部修改传入的参数值进行修改,
|
||
函数执行后,并不会对外部变量`a` 发生修改。
|
||
|
||
这个例子确实说明了函数参数是按值传递的。
|
||
|
||
但是再来看另一个例子:
|
||
|
||
**示例2**
|
||
```js
|
||
var obj1 = {
|
||
a: 1
|
||
}
|
||
function foo(arg) {
|
||
arg.a = 2
|
||
console.log(arg)
|
||
}
|
||
foo(obj1) // { a: 2 }
|
||
console.log(obj1) // { a: 2 }
|
||
|
||
var obj2 = {
|
||
a: 1
|
||
}
|
||
function bar(arg) {
|
||
arg = 2
|
||
console.log(arg)
|
||
}
|
||
bar(obj2) // 2
|
||
console.log(obj2) // { a: 1 }
|
||
```
|
||
|
||
在这个例子中, 函数`foo` 执行完后, 打印的 `obj1` 值发生了变化,说明函数`foo` 内部修改了外部变量`obj1`,
|
||
为什么会发生修改?而在 函数`bar` 执行后,`obj2` 值保持不变,这又是为什么? 函数参数是否真的是 **按值传递**?
|
||
|
||
那么该如何理解 `函数参数是按值传递的`?
|
||
|
||
在理解这个之前,我们首先需要知道,`JavaScript` 的数据类型,以及不同数据类型的存储方式。
|
||
|
||
## 数据类型及其存储方式
|
||
|
||
我们知道, 在 `JavaScript` 中, 有两种 数据类型,分别是:**(1)基本数据类型**和 **(2)引用数据类型**,
|
||
|
||
- 基本数据类型:值 直接保存在 **栈(stack)** 中。
|
||
```js
|
||
let a = 1
|
||
let b = a
|
||
a = 2
|
||
console.log(a, b) // 2 1
|
||
```
|
||
基本类型在 **栈** 中的赋值变动如下:
|
||
::: center
|
||
{ style=width:500px; }
|
||
:::
|
||
|
||
- 引用数据类型:值 保存在 **堆(heap)** 中, 并在 **栈(stack)** 中保存 值 在 **堆(heap)** 中的内存地址。
|
||
|
||
```js
|
||
let a = { name: 'Mark' }
|
||
let b = a
|
||
b.name = 'John'
|
||
console.log(a) // { name: 'John' }
|
||
```
|
||
引用类型在 **栈** 和 **堆** 中的复制变动如下:
|
||
::: center
|
||
{ style=width:680px; }
|
||
:::
|
||
|
||
## 按值传递
|
||
|
||
我们从 数据类型来理解 `按值传递`, 那么可以发现, **传递** 的值, 是指在 **栈(stack)** 中保存的值。
|
||
|
||
即, 无论 **参数值** 是 基本数据类型还是引用数据类型, **传递** 的是 **栈(stack)** 中的值。
|
||
|
||
- 对于基本数据类型, 函数内部修改参数的值,实际上是修改的是 函数参数重新在 **栈(stack)** 中的内存片段保存的值。
|
||
|
||
- 对于引用数据类型, 函数参数 传递是的 引用类型在 **栈(stack)** 中的内存地址:
|
||
- 如果直接修改参数的值,函数参数在 **栈(stack)** 中的内存片段保存的内存地址被覆盖。
|
||
- 如果修改 参数对象的属性值,修改的是根据 函数参数在 **栈(stack)** 中的内存片段保存的内存地址对应的在 **堆(heap)** 中的值。
|
||
|
||
所以回头重新看 **示例1** 和 **示例2**, 均正确表述了 函数的参数是 **按值传递** 的。
|