zoukankan      html  css  js  c++  java
  • javascript中所有函数参数都是按值传递

    在看《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深入之参数按值传递

    内存空间详解

  • 相关阅读:
    20165308实验三 敏捷开发与XP实践实验报告
    20165308 《Java程序设计》第9周学习总结
    20165308 四则运算2
    20165308 实验二 Java面向对象程序设计
    20165308第八周学习总结
    20165308课上补做
    20165308 结队训练
    20165308《Java程序设计》第7周学习总结
    2018-2019-1 20165320 《信息安全系统设计基础》第七周学习总结
    2018-2019-1 20165320 《信息安全系统设计基础》第六周学习总结
  • 原文地址:https://www.cnblogs.com/weiqinl/p/9497744.html
Copyright © 2011-2022 走看看