首页 >社区问答列表 >javascript - 这段代码中a的值为什么没有改变?

javascript - 这段代码中a的值为什么没有改变?

对比两处,有个疑惑,为什么把a当作参数传入以后 a值在全局中没有变化呢?

var a = 1;
function b(){ 
   a = 2;
   console.log(a);   //2
}
b();
console.log(a);  //2

var a = 1;
function b(a){  //此处有传参
   a = 2;
   console.log(a);   //2
}
b();
console.log(a);  //1  ?

  • 高洛峰
  • 高洛峰    2017-04-10 16:25:067楼

    • 基本类型只传值。

    var a= 1;
    b=a
    b=2
    console.log(a) //1
    console.log(b) //2
    • 函数参数声明会函数作用域中的覆盖同名变量引用

    var a = 1;
    function foo(a){
        console.log(a) 
    }
    
    foo("haha") // "haha" 指的是函数的参数a
    console.log(a) //1 外部作用域中的a

    楼主想要实现所述的功能,应该这样把他们区分出来,这涉及到一些变量命名的规范等等,在开发中应该是有相关约定的,同名覆盖的事情应该避免

    var a = 1;
    function foo(sth){
        a=sth;
        console.log(sth)
    }
    
    console.log(a) //1;
    foo(2) //2
    console.log(a) //2

    +0添加回复

  • 回复
  • 阿神
  • 阿神    2017-04-10 16:25:066楼

    总的来讲,因为javascript是call by value(https://en.wikipedia.org/wiki/Evaluation_strategy)的,所以就算你传了一个变量进参数里,你在函数里面修改了参数,这个变化是不会反映在外面的变量上面的。就算他们是同一个名字也没有用。如果你要这么干的话,你可能需要传入array或者是map,用来模拟其他的编程语言的引用或者是指针的功能。

    历史上Algol语言就是使用call by name的,所以默认语言就有题主想要的这个功能。这篇文章(http://www.cs.sfu.ca/~cameron/Teaching/383/PassByName.html)介绍了他如何实现call by name的。首先编译器会检查什么参数会被改,如果发现有,那就把对参数的读写都换成指针。翻译成javascript差不多就是(没有指针只好用getter/setter来模拟了,就像C++STL的iterator):

    var a = 1;
    function b(aRef) {
        aRef.write(2);
        console.log(aRef.read());
    }
    b({read:function(){return a;}, write:function(x){a=x;}});
    console.log(a);

    +0添加回复

  • 回复
  • ringa_lee
  • ringa_lee    2017-04-10 16:25:065楼

    对于这种故意弄出来整我们新人的题目,我真是恨透了。

    谁脑残会写出这种给传入参数重新赋值的函数啊?有什么用吗?

    function b(a) {
        a = 2;
        console.log(a);
    }

    我们知道,传入的参数,都会代表一个具体的值,可能是数值,字符串,数组,函数,对象等。可是有谁见过把传入的参数当成变量还要接受别人重新赋值的用法啊?

    这个b函数中的参数a,和函数体中a=2的a,到底是不是同一个a啊?假如换个参数传入呢

    var a = 1;
    function b(c){
       a = 2;
       console.log(a);  
    }
    b();
    console.log(a);

    是不是结果和题主第一个例子又一样了啊。

    如果我们这样调用b(4);
    b函数难道就会变成这样?

    function b(4) {
        4 = 2;
        console.log(4);
    }

    当然别人设计编程语言的时候也会想到总有一些神经病的人会做这些可怕的事情,只好对这种情况做一个特殊处理了。
    当传入参数的值在函数声明的作用域中已经存在时,作用域中该变量的值,不会在函数体中被修改。

    比如我们常见的window对象

    var a = { f: 1, m: 2 }
    function b(window) { 
        window = a; 
    }
    b();

    运行后window指向任然不变。

    以及jQUery源码中

    (function(window, undefined) {
        ...
    })(window)

    因此个人理解是,没有什么为什么,就是javascript在设计之初,对这种情况的一个特殊处理。防止程序员乱来。

    +0添加回复

  • 回复
  • 迷茫
  • 迷茫    2017-04-10 16:25:064楼

    var a = 1;
    function b(a){ //此处有传参
    a = 2;
    console.log(a); //2
    }
    b();
    console.log(a); //1 ?

    这个参数a相当于b中的局部变量,它和全局中的a不是一个变量.

    +0添加回复

  • 回复
  • 迷茫
  • 迷茫    2017-04-10 16:25:062楼

    题主应该是学生,说多了你难理解。这种题目考察两个重要知识点:变量作用域、值传递和引用传递。请自己百度加深理解。

    +0添加回复

  • 回复
  • 阿神
  • 阿神    2017-04-10 16:25:061楼

    这应该涉及到javascript作用域链和活动对象。
    每调用一次函数,就会创建一个函数上下文。在函数上下文里面有个作用域和活动对象。活动对象包含函数内部的变量,函数定义声明,和函数参数。
    var a = 1;
    function b(){
    a = 2;
    console.log(a); //2
    }
    b();
    console.log(a); //2

    +0添加回复

  • 回复