JavaScript函数参数都是按值传递的理解

382 阅读4分钟

一、基本类型和引用类型的值

1、ECMAScript变量包含两种不同数据类型的值:基本类型值和引用类型值。
2、基本类型值指的是5种基本数据类型Undefined、Null、Boolean、Number和String,为什么叫基本类型值,因为这五种数据类型是按值访问的,可以操作保存在变量种的实际的值。
3、引用类型的值是保存在内存中的对象,ECMAScript不允许直接访问内存中的位置,也就是不能操作保存在内存中的对象。我们使用JavaScript操作对象的时候,实际上是在操作对象的引用而不是实际的对象
4、总而言之,在JavaScript里,5种基本数据类型是按值访问的,而对象这种引用类型的值是按引用访问的。其他语言中字符串是以对象来表示所以是引用类型,但是ECMAScript中字符串是按值访问的是基本类型。

二、基本类型与引用类型的不同之处

1、动态属性,引用类型的值可以添加删除属性和方法,基本类型的值不可以。
<script type="text/javascript">
    var person = new Object();
    person.name = "Nicholas";
    alert(person.name); // "Nicholas"


    var name = "Nicholas";
    name.age = 27;
    alert(name.age);     //undefined
</script>
2、复制变量值,基本变量在复制变量值的时候,会创建一个新变量,然后把原先的值复制一份再赋值给新变量。之后两个变量完全独立。而引用类型同样也会创建一个新变量,把原先的引用类型的值复制一份再赋值给新变量。跟基本变量复制一样,不同的是,引用类型的值是一个指针,所以新旧两个变量都指向内存中的同一个对象,所以改变其中一个变量就会影响另一个变量。

image.png

基本类型复制

引用类型复制
3、参数传递,ECMAScript中变量复制有引用类型复制和基本类型复制,但是ECMAScript中的参数传递都是值传递,不管你传递的是基本类型还是引用类型。对于传递基本类型参数来说,跟基本类型复制一样的原理,count和num是互不影响的。
<script type="text/javascript">

    function addTen(num) {
        num += 10;
        return num;
    }

    var count = 20;
    var result = addTen(count);
    alert(count);   //20,没有变化
    alert(result);  //30
</script>
对于传递引用类型参数来说,修改了函数局部变量的值同样也会修改外部变量的值(如下),那这不就是“引用传递”吗?
  function setName(obj) {
        obj.name = "Nicholas";
    }

    function setName(obj) {
        obj.name = "Nicholas";
        return obj;
    }

    var person = new Object();
    var personNew = setName(person);
    alert(personNew.name);      //"Nicholas";
    alert(person.name);         //"Nicholas";

不是的,首先我们要分清值传递和引用传递,值传递就是把原来的值拷贝一份,这两份互不影响,而引用传递是直接把引用传进去,没有再拷贝一份!所以,在JavaScript中,为什么说所有函数都是值传递,因为对于基本类型,它就是拷贝一份值再传进去互不影响,而对于引用类型,它也是再拷贝一份地址再传进去,这份地址和之前的地址都指向同一个对象,所有才会出现上面代码中的这种情况。
在看看下面的代码,obj在没有重新赋值之前和外面的person一样都是指向内存堆里的同一个对象,所以第二个继续输出Nicholas,当obj再重新指向新对象的时候,我们要记住obj和person是内存栈里的两个不同的值。所以改变了obj指向的对象,并不会改变person指向的对象。如果是引用传递就没有再拷贝一份而是直接传递person这个引用,所以下面输出都会是ljs。
    function setName(obj) {
        obj.name = "Nicholas";
        obj = new Object();
        obj.name = "ljs";
        return obj;
    }

    var person = new Object();
    var personNew = setName(person);
    alert(personNew.name); //"ljs";
    alert(person.name); //"Nicholas";

三、检测类型

在javascript中,检测基本类型使用typeof,检测对象类型使用typeof都会返回object(null也返回object),想知道对象确切的类型可以使用instanceof。需要注意的是null的typeof是object,但是null的instanceof object是false,这是个历史遗留问题,null不是以object为原型创建,记住就行了。
<script type="text/javascript">
    var s = "Nicholas";
    var b = true;
    var i = 22;
    var u;
    var n = null;
    var o = new Object();
    var a = new Array();
    var r = new RegExp();

    alert(typeof s); //string
    alert(typeof i); //number
    alert(typeof b); //boolean
    alert(typeof u); //undefined
    alert(typeof n); //object
    alert(typeof o); //object
    alert(typeof a); //object
    alert(typeof r); //object
    alert(o instanceof Object); //true
    alert(n instanceof Object); //false
    alert(a instanceof Object); //true
    alert(r instanceof Object); //true
</script>