在看《JavaScript高级程序设计》(第三版)的时候,传递参数这一节,里面提到

ECMAScript中所有函数的参数都是按值传递的

它自己的解释是,

把函数外部的值复制给函数内部的参数,就和把值从一个变量复制到另一个变量一样。

基本类型值的传递如同基本类型变量的复制一样,

而引用类型值的传递,则如同引用类型变量的复制一样。

我们先明白几个概念,之后再讨论。

数据类型

基本数据类型,有6种,Undefined、Null、Boolean、Number、String、Symbol

引用类型,Object、Array、Date、RegExg、Function等

数据类型介绍,可以参考JavaScript数据类型的非常6+1

内存空间

var a = 2
var b = 'abc'
var c = true
var d = {value : 1}
var e = [1, 2, 3]

定义的以上几个变量,在内存中,所占用的空间如图示意:

基础数据类型值,在栈中存储实际的值。引用数据类型值,在栈中存储引用地址值,在堆中存储实际的值。

赋值拷贝/复制

基础数据类型,赋值拷贝,拷贝实际值


var a = 1 var b = a b = 2 console.log(a) // 1

引用类型,赋值拷贝,拷贝引用地址,浅拷贝。可以参考javascript中的浅拷贝ShallowCopy与深拷贝DeepCopy


var a = {value : 1} var b = a b.value = 2 console.log(a.value) // 2

举例分析

明白了以上几个概念,我们再来说说,把函数外部的值复制给函数内部的参数,就和把值从一个变量复制到另一个变量一样。也就是一个赋值复制过程。我们举几个例子分析下。

1. 传递基础类型,函数中不修改参数类型


var a = 1 function func(o) { o = 2 console.log(o) } func(a) // 2 console.log(a) // 1

这里的func函数,传递了一个参数o,而参数实际上是函数的局部变量。那么,我们就可以修改函数


var a = 1 function func() { var o = a // 函数内部的参数变量,赋值函数外部的值 o = 2 // 修改内部变量的值 console.log(o) } func(a) // 2 console.log(a) // 1

可以得到相同的结果。他们在内存中的变化,如图示意:

从以上图中,我们能清楚的看出,变量a一直等于1,而变量o,由于赋值之后,复制了a的实际值,在内存中开辟了空间,存储在栈中。再执行func函数,修改变量o的值,只会影响其自身。

2. 传递基础类型,函数中修改类型


var a = 1 function func(o) { o = {value : 1} console.log(o) }
func(a) // {value: 1} console.log(a) // 1

同理,我们也可以修改这里的函数


var a = 1 function func() { var o = a // 函数内部的参数变量,赋值函数外部的值 o = {value : 1} // 修改内部变量的值 console.log(o) // {value: 1} }
func() // {value: 1} console.log(a) // 1

内存中的变化示意图:

从以上图中,我们能清楚的看出,变量a一直等于1,而变量o,由于内部参数赋值之后,复制了a的实际值,在内存中开辟了空间,存储在栈中。再执行func函数,修改变量o的值,只会影响其自身。

3. 传递引用类型,函数中不修改类型


var a = { value : 1 } function func(o) { o.value = 2 console.log(o) } func(a) // { value : 2} console.log(a) // {value : 2}

同理,我们也可以修改这里的函数


var a = { value : 1 } function func() { var o = a // 函数内部的参数变量,赋值函数外部的值 o.value = 2 // 修改内部变量的值 console.log(o) // {value: 2} }
func() // {value: 2} console.log(a) // {value: 2}

内存中的变化示意图:

从以上图中,我们能清楚的看出,由于变量a是引用类型,通过函数内部参数的赋值复制,传递了引用地址值,那么变量ao会指向同一个内存对象。再执行func函数,修改变量o在堆内存中的值,并没有修改在栈中的引用地址的值。这样,由于变量o和变量a使用的是同一个引用地址,也就是同一个堆内存中的值,那么变量a的值,也就会随着变量o的变化而变化了。

4. 传递引用类型,函数中修改类型


var a = {value : 1 } function func(o) { o = 2 console.log(o) } func(a) // 2 console.log(a) // { value : 1}

接下来,我们也可以修改这里的函数


var a = { value : 1 } function func() { var o = a // 函数内部的参数变量,赋值函数外部的值 o = 2 // 修改内部变量的值 console.log(o) // 2 }
func() // 2 console.log(a) // {value: 1}

内存中的变化示意图:

由于变量a是引用类型,通过函数内部参数的赋值复制,传递了引用地址值,那么变量ao会指向同一个内存对象。再执行func函数时,改变了变量o的数据类型,变成了基础数据类型,也就切断了引用。这样,变量ao就没有关系了。

总结

JavaScript中所有函数参数都是按值传递的。基本类型值,传递的是实际值,引用类型,传递的是引用地址值。

参考

JavaScript深入之参数按值传递

内存空间详解

javascript中所有函数参数都是按值传递的更多相关文章

  1. JavaScript中Function函数与Object对象的关系

    函数对象和其他内部对象的关系 除了函数对象,还有很多内部对象,比如:Object.Array.Date.RegExp.Math.Error.这些名称实际上表示一个 类型,可以通过new操作符返回一个对 ...

  2. Javascript中的函数(Function)与对象(Object)的关系

    今天我们来尝试理解Function和Object.因为这个里面有些人前期可能会搞糊涂.他们之间到底是什么关系.当然也不除外当初的我. 注意:官方定义: 在Javascript中,每一个函数实际上都是一 ...

  3. javascript中所有函数的参数都是按值传递的

    [javascript中所有函数的参数都是按值传递的] 参考:http://www.jb51.net/article/89297.htm

  4. 《JavaScript高级程序设计》读书笔记--ECMAScript中所有函数的参数都是按值传递的

    ECMAScript中所有函数的参数都是按值传递的.也就是说把函数外部的值复制给函数内部的参数(内部参数的值的修改不影响实参的值). 基本类型变量的复制: 基本类型变量的复制,仅仅是值复制,num1和 ...

  5. javascript中的所有内容都是一个对象:字符串、值、数组、函数…

    javascript中的所有内容都是一个对象:字符串.值.数组.函数…此外,javascript允许自定义对象.javascript对象JavaScript提供多个内置对象,如字符串.日期.数组等.对 ...

  6. JS对象 JavaScript 中的所有事物都是对象,如:字符串、数值、数组、函数等,每个对象带有属性和方法。

    什么是对象 JavaScript 中的所有事物都是对象,如:字符串.数值.数组.函数等,每个对象带有属性和方法. 对象的属性:反映该对象某些特定的性质的,如:字符串的长度.图像的长宽等: 对象的方法: ...

  7. JavaScript中Eval()函数的作用

    这一周感觉没什么写的,不过在研究dwz源码的时候有一个eval()的方法不是很了解,分享出来一起学习 -->首先来个最简单的理解 eval可以将字符串生成语句执行,和SQL的exec()类似. ...

  8. Javascript中的函数

    Javascript中的函数 1.什么是函数 函数是被命名的,独立的,完成特定功能的代码段.其可能给调用它的程序返回值,我们把这个代码段就称之为"函数". 被命名的:函数大部分都是 ...

  9. 浅析 JavaScript 中的 函数 currying 柯里化

    原文:浅析 JavaScript 中的 函数 currying 柯里化 何为Curry化/柯里化? curry化来源与数学家 Haskell Curry的名字 (编程语言 Haskell也是以他的名字 ...

随机推荐

  1. 服务器配置 ssl 证书

    最近因为公司的 服务器 ssl证书即将到期(服务器 和 ssl证书管理都在 腾讯云上), 所以为了能顺利的 重新申请 ssl证书 ,我和小伙伴 在他的个人服务器上尝试了一波(我们居然都不会 ...) ...

  2. 实验一 Java开发环境的熟悉(Linux + Eclipse)

    学号 20175206 实验一 <Java开发环境的熟悉>实验报告 实验内容 1.使用JDK编译.运行简单的Java程序: 2.使用Eclipse 编辑.编译.运行.调试Java程序. 实 ...

  3. Linux下nc命令的使用

    nc命令的作用 实现任意TCP/UDP端口的侦听,nc可以作为server以TCP或UDP方式侦听指定端口 端口的扫描,nc可以作为client发起TCP或UDP连接 机器之间传输文件 机器之间网络测 ...

  4. django环境部署 crm和路飞学城

    环境依赖 yum install gcc patch libffi-devel python-devel zlib-devel bzip2-devel openssl-devel ncurses-de ...

  5. Axure PR的使用

    1759139 王越 Axure RP是美国Axure Software Solution公司旗舰产品,是一个专业的快速原型设计工具,让负责定义需求和规格.设计功能和界面的专家能够快速创建应用软件或W ...

  6. 线段树——习题、lazy解析

    习题: C. Cloud Computing lazy操作解析:

  7. MyRolan (快速启动小工具)

    类似 Rolan的快速启动工具. 启动后隐藏,当鼠标移至左上角时,窗口显示,点击项目可运行程序. GitHub地址: MyRolan . #if defined(UNICODE) && ...

  8. 秋名山老司机(BS4与正则的比拼)

    因为嘉伟思杯里的一个脚本题目,16进制计算,python3正则还没学,所以没写出来.大佬跟我说也可以用BS4,从DOM上下手,直接爬下来直接一个eval就搞定了,eval可以像这样计算16进制,eva ...

  9. 使用SpringSecurity体验OAuth2 (入门2)

    本文继续使用SpringSecurity从实战角度对OAuth2进行体验,上一篇 搭建了项目环境,并对配置做了初步分析,分析发现会有两套配置可能在影响OAuth,一个是由授权服务的启动类上的注解@En ...

  10. GYM 100608G 记忆化搜索+概率 2014-2015 Winter Petrozavodsk Camp, Andrew Stankevich Contest 47 (ASC 47)

    https://codeforces.com/gym/100608 题意: 两个人玩游戏,每个人有一个长为d的b进制数字,两个人轮流摇一个$[0,b-1]$的骰子,并将选出的数字填入自己的d个空位之中 ...