先明确一个概念:栈和堆;不要管他们是什么,你知道有这两个东西就行;

var num1 = 8;

  实际上,声明的num1这个变量它并没有直接在栈中保存一个值:8;

  当你var 声明的时候,在堆中会被分配出一块内存空间,这个空间有两个信息,一个是这个空间在堆中的地址,另一个是这个空间实际保存的一个值:8;

  而栈中,给了两个信息,有一个标识符叫做num1,它里面被放进去了一个堆中的地址,这个地址,就指向堆中那个对应的保存着值:8的那块内存空间;

  

  

var num1 = 8; var num2 = num1;

  声明了一个变量num1,值为8,值在内存空间里;

  声明了一个变量num2,值为num1的值,将num1的值在内存空间中复制一份,然后将复制的那一份内存空间的地址放入栈中的num2;

  如果这个时候我修改了num2的值,num1是不会改变的,为什么?

  A有两个儿子,一个叫B另一个叫C,A先给了B一百元钱,这个时候C看见了也想要,但是A就只有100元,于是A就用超能力,将B的一百元复制了一张给了C;

  这个时候,B和C都各自有一百元,但是C花了5块钱买了一个棒棒糖,还剩95元,C花的是自己口袋里的那一百元,不是B口袋里的,所以B没有买棒棒糖,B的口袋里还是一百元,没有变;

  

  【值传递】

  ————————————————————————————————————————————————————————————————————

  在《JavaScript高级程序设计》中,我读到这么一段话:在ECMAScript中,所有函数的参数都是【值传递】,不是【引用传递】;

  先解释什么是【值传递】:上面的num1和num2就是值传递;

  举个例子: 

复制代码 var a = 10; function foo(num){ return num + 1; }; console.log(foo(a));//11 console.log(a);//10 复制代码   函数foo接受一个num参数,在函数体内将传递进来的这个参数加1并返回出去;

  这个时候,其实num就是一个变量,就是一个相对于foo这个函数的局部变量,你可以这么理解:var num = a;

  函数的参数是无法在函数外部获得或使用的;

  都说了是值传递,所以他是将a的值复制了一份赋给了num,【num的地址指向和a的地址指向在堆中是不同的】,既然都不在同一个内存空间内,那我改变其中一个内存空间的值,是不可能影响到另一个内存空间的值的;

    

  实在是理解不了,看这段代码:

复制代码 var {log} = console;

    let nameArr = ['小红','小李'];

    function add(arr){
        log(arguments);
    };

    add(nameArr);            

复制代码   啥意思呢?

  你肯定还记得arguments,本质上函数的参数列表是一个数组,不是说值传递吗?你把【值传递】倒过来看【传递值】;

  对,没错,传递的是值,不是地址;

  【引用传递】

  ————————————————————————————————————————————————————————————————————

  举个例子,看代码你就明白了:

复制代码 var obj0 = { name:'小明' }; var obj1 = obj0; console.log(obj0.name);//小明 console.log(obj1.name);//小明 复制代码   对象obj0有个name属性,值为字符串:小明;

  我又创建了一个obj1对象,将obj0赋值给obj1;

  那么,在堆中,是有两个内存空间分别保存着两个对象吗?

  不是的,其实是这样的;

  这个赋值,其实只是把obj0的地址赋给了obj1,但实际上,在堆中,并没有一个独立的对象让obj1去单独指着,obj0和obj1的地址共同指向了堆中的同一个对象;

  这样说的话,那么我不管是在其中任何一个对象上做出修改,都会同时影响另外一个,另一个的相同属性也会跟着改变;

  就是说,当复制保存对象的某个变量的时候,操作的是对象的引用(地址),当修改添加对象的属性/方法时,操作的是实际的对象本身;

  

  前方有坑,需谨慎:

  

复制代码 var fun = { name:'小红' } function setName(obj){ obj.name = '老王' } setName(fun); console.log(fun.name);//老王 复制代码

  有个fun对象,这个对象有个name属性,值为"小红";

  执行setName这个函数,将fun这个对象传递了进去,这个时候是值传递还是引用传递?

  想都不用想,肯定是值传递,因为【JS中所有的函数的参数都是值传递】;

  那既然是值传递,我在函数内部修改了obj这个对象的name是不是不会影响到外面fun对象的name属性;

  按道理来说,肯定是这样的,但是偏偏就不是,在外面输出了fun的name属性,发现被更改了;

  实际上是这样的:var obj = fun;

  即使函数的参数是只能值传递,但是obj也会按引用访问同一个对象;

  

  这里非常的不好理解

  这样想,纯正的将一个对象赋值为另外一个对象,改变其中一个的某个属性,另一个也会同时发生改变,因为他们是指向了堆中的同一个对象;

  上面代码中:函数的参数实际上是一个局部变量,只对函数体内起作用;

  而代码中将fun的值,传递给局部变量obj,那么就是这样:var obj = fun;

  实际上,你在setName这个函数中将arguments打印出来你是可以看到,obj的值是一个对象{name:'小红'};这就更加的进一步证实,JS函数中的参数确实都是值传递;

  这就对上了,函数的参数都是值传递,没错,确实是fun的值;

  最后:在向参数传递引用类型的值的时候,会把这个值在内存中的地址也一并复制一份给局部变量(就是参数);

  然后你就能明白这句话:obj还是会按照引用,就是地址,去访问这个对象,访问的地址相同,那肯定的,访问的对象也就是同一个对象了!

  

  然后,然后现在你就已经理解了什么是基本类型值、引用类型值,什么是值传递,什么是引用(地址)传递;