首页 > 试题广场 >

以上 JavaScript 代码,在浏览器中运行的结果是

[单选题]
var foo = {n:1};
(function(foo){
    console.log(foo.n);
    foo.n = 3;
    var foo = {n:2};
    console.log(foo.n);
})(foo);
console.log(foo.n);


以上 JavaScript 代码,在浏览器中运行的结果是

  • 1 2 3
  • undefined 2 1
  • 报错
  • 1 2 1
推荐

A

  • 第一步:进行预编译,var全局变量foo、匿名函数 function、var局部变量foo
  • 第二步:代码自上而下、自左向右执行计算:
  1. 对全局变量foo进行赋值foo={n:1};注意:此值为对象,属于引用类型;
  2. 匿名函数传入参数foo={n:1}自执行;
  3. console.log(foo);打出数字1;
  4. 由于存在foo局部变量,那么对foo变量进行赋值foo={n:3},同时更改了引用类型的参数值,全局foo变量被重新赋值foo={n:3};
  5. 对局部变量foo进行重新赋值foo={n:2};
  6. console.log(foo);打出数字2;
  7. 全局变量foo={n:3},因此,console.log(foo);打出数字3;
编辑于 2016-12-25 22:13:22 回复(14)


var foo = {n:1};
(function(foo){            //形参foo同实参foo一样指向同一片内存空间,这个空间里的n的值为1
    var foo;               //优先级低于形参,无效。
    console.log(foo.n);    //输出1
    foo.n = 3;             //形参与实参foo指向的内存空间里的n的值被改为3
    foo = {n:2};           //形参foo指向了新的内存空间,里面n的值为2.
    console.log(foo.n);    //输出新的内存空间的n的值
})(foo);
console.log(foo.n);        //实参foo的指向还是原来的内存空间,里面的n的值为3.

编辑于 2017-02-07 17:31:53 回复(27)
首先执行匿名函数,这里的foo.n就是值全局的foo.n,所以输出1,之后foo.n=3,接着定义了一个局部变量foo.n=2,输出2 执行匿名函数完之后,紧接着输出的是全部的foo.n,这时候因为在匿名函数中修改了值,所以输出3
发表于 2018-04-10 10:11:21 回复(0)

知识点:JavaScript的hoisting机制

本质:只提升声明部分

例子

1.我是变量声明,我会被提升在作用域顶端!

var a;

2.我是变量定义,我的声明部分会被提升,赋值部分不会被提升!

var b = 'test';

3.我是函数定义,或者叫我函数表达式。其实我就是变量定义,只不过恰好被赋值的类型是函数,所以也只提升变量名不提升函数值

var c = function() {
    console.log('test');
}

4.我是函数声明,所以我全部被提升了,包括函数名和函数体。另外,我的优先级比变量声明要高,名字和我相同的变量声明会被忽略!

function d() {
    console.log('test');
}

题目

参数是引用参数

var foo={n:1};
(function (foo) {
    console.log(foo.n);
    foo.n=3;
    var foo={n:2};
    console.log(foo.n);
})(foo);
console.log(foo.n);

结果: 1 2 3

参数是传值参数

var foo=1;
(function (foo) {
    console.log(foo);
    foo=3;
    var foo=2;
    console.log(foo);
})(foo);
console.log(foo);

结果:1 2 1

解释:

var foo={n:"我是形参或全局变量"};
(function (foo) {
    console.log(foo.n);
    foo.n="我改变了参数和全局变量";
    var foo={n:"我是局部变量"};
    console.log(foo.n);
})(foo);
console.log(foo.n);
发表于 2017-01-10 20:28:38 回复(14)
var foo = {n:1};           //定义全局变量
(function(foo){            //形参foo同实参foo一样指向同一片内存空间,这个空间里的n的值为1
    var foo;                   //如果在局部变量中定义了一个和形参相同名字的变量,对该局部变量的操作会反映到形参的那个变量中去
    console.log(foo.n);   
    foo.n = 3;                 //局部foo指向的内存空间(目前为全局 )里的n的值被改为3
    foo = {n:2};               //局部foo重新指向了新的内存空间,里面n的值为2.
    console.log(foo.n);   //输出局部foo内存空间的n的值
})(foo);
console.log(foo.n);        //输出全局里的foo.n值
发表于 2017-04-18 14:02:55 回复(3)

以下图片只是方便理解而已,如有错误欢迎指出,谢谢。文字解析还有变量提升等问题可以参考下面几位大大的解析:@demo亮; @SuperluminalSnalis; @君寻不惑;
图片说明
图片说明
图片说明
图片说明

发表于 2017-09-12 09:41:17 回复(5)
1、函数参数是原始类型的值(数值、字符串、布尔值),传递方式是传值传递,即在函数体内修改参数值,不会影响到函数外部。
2、函数参数是复合类型的值(数组、对象、其他函数),传递方式是传址传递,传入的是原始值的地址,因此在函数内部修改参数,将会影响到原始值。
注意,如果函数内部修改的,不是参数对象的某个属性,而是替换掉整个参数,这时不会影响到原始值!

编辑于 2017-09-12 10:00:08 回复(3)

此处混淆和难度的提高,就在于这里的各个地方都用了foo。其实我们可以发现,函数内和函数外的联系,只在于传递了引用,为了关注函数内部参数名和局部变量名重复的问题,可以把代码转变一下:
var foo = {n:1};
(function(foo2){
  console.log(foo2.n);//foo2=foo的引用地址,输出1
  foo2.n = 3;  //更改引用地址处的n为3
  var foo2 = {n:2};//foo2不用foo给它的地址了,指向了一个新地址(函数参数和局部变量同样处理,即参数已经起到声明作用,此处只余赋值)
  console.log(foo2.n);//把指向的新地址的值取出来,输出2
})(foo);
console.log(foo.n);//虽然foo2指向了一个新的引用地址,但是foo指向的引用地址还是原来的老地址,所以为3
发表于 2019-12-25 23:27:38 回复(0)

根据题目修改一下好理解
var foo = {n:1};
            (function(foo){            
                var foo;               //形参其实也是在该函数作用域内也声明了一个变量,即使在函数内再次声明
                // 但是如果第二次声明没有赋值的话,还是会使用有赋值的形参
                 console.log(foo);    // 此时使用形参,结果{n: 1};因为使用第二次声明的会undefined,
                console.log(foo.n);    // 此时使用形参
                foo.n = 3;             //此时也是使用形参,因为对于第二次声明的变量来说,
                // 还没有添加属性n,所以使用n属性就会寻找形参中的属性n
                
                
                foo = {n:2};           //而此时给第二次声明的变量添加属性n
                foo.n=4;        //此时就会根据就近原则使用第二次声明的变量foo,而不是形参
                console.log(foo.n);    //4
            })(foo);
            console.log(foo.n);        //实参foo的指向还是原来的内存空间,里面的n的值被修改为3.
            
发表于 2019-08-05 20:54:48 回复(2)
ZAZ头像 ZAZ
var foo = { n: 1};
(function(foo) {
// 这里是变量提升, 不懂的话现在记住了.
// 我查阅了文档, 一个函数的形参的声明是优先于内部代码中的变量声明之前的, 所以这一行相当于无效.
var foo;
// 这里理所应当是 "1"
console.log(foo.n);
// 首先, 局部变量优先于外部变量所以这里是形参声明的 foo, 没疑问吧 ?
// 我查阅文档说明: 形参实际上是一个新声明的变量, 赋值为实参也就是外面的 foo
// 但是在 javascript 中将对象赋值给变量, 这个变量其实是个引用, 引用就是个地址, 赋值给形参中的 foo 时
// 其实也就是让形参 foo 也指向对象 { n: 1}. 此时 foo.n = 3 将直接修改这个
// 外部的 foo 指向的对象 (也是内部的 foo 此时指向的对象)
foo.n = 3;
// 这里前面也提到了. 形参中的 foo 其实是一个已经隐含声明的变量, 且 inner 的优先级高于 outer
// 所以此时就是将形参指向另一个对象 { n: 2 };
foo = { n: 2 };
// inner 高于 outer, 所以读取的是形参的值 "2"
console.log(foo.n);
}(foo));
// 之前在函数中被引用改变了, foo.n = 3. 所以此时结果为 "3"
console.log(foo.n);

发表于 2017-05-21 21:04:12 回复(1)
答案是A,foo.n = 3,只是改变了函数外定义对象的某个属性,没有改变foo的指向,所以函数外部的foo的n值改完3,var foo = {n: 2},这个赋值已经改变了foo引用指向,foo此时已经指向另外一个对象,函数外部定义的foo没有被改变,所有最后一次输出是3,前两次输出显而易见
发表于 2016-12-23 09:23:24 回复(0)
在js高程p185里面有提到一个例子类似这题重新声明的变量foo,它的解释是js从来不会告诉你是否多次声明了同一个变量,遇到重新声明变量,它只会对后续的声明视而不见(不过,它会执行后续声明中的变量初始化)。
发表于 2017-04-07 23:37:29 回复(0)
你们都在说什么啊? 大家肯定都是卡在那个var提升上了  这里不是什么乱七八糟的“变量的声明会被忽略” 
请看下面代码
 var x=1;
(function(x){
      console.log(x)//1
      var x=2
      console.log(x)//2
  })(x)


 var x=1;
  (function(x){
      console.log(x)//undefined
      var x=2
      console.log(x)//2
  })()

看到区别了吗 所以题目你去掉自调用参数传进来那个foo 是会报错的 因为你尝试读取undefined.n!

编辑于 2022-03-19 00:26:51 回复(1)
看了一圈, 前排的热门解析基本都有没说到点上或有错误的地方.
首先, js 的传参机制是这样的: 
1. 无论值类型还是引用类型都是按值传参的(并非前排有的说对象按引用传);
2. 对值类型, 传参时会复制值本身, 因此在函数中改变形参不会影响外面的值;
3. 对引用类型, 传参时复制的是地址, 也就是说, 此时有栈中有两个指针指向外面的那个对象(可以看图好好理解一下这句话). 
4. 因此, 对形参的直接赋值, 只会修改复制过来的那个栈指针的指向, 不会影响被复制的栈指针.
5. 但是, 对形参某一属性的修改, 由于复制过来指针指向的是依然是原对象, 因而会修改原对象. 
另外, var foo; 虽然提升了, 但 foo 本来就有值所以被忽略了.

                                                                                                                                                                                                                                                                                                                                                                           
发表于 2021-08-14 13:26:07 回复(2)
全局变量  &  形式参数  &  局部变量  &  同名变量  &  变量提升
若变量有值,则对变量的重新声明会被忽略
        函数中,全局变量值,同名局部变量的声明有效——函数内对变量操作,仅仅与局部变量有关不影响全局变量
        函数中,全局变量值,同名局部变量的声明被忽略——函数使用的变量实际是全局变量,具体情况分两种
            ①  变量为引用数据类型,引用传递,在声明前直接对变量操作会影响变量(如foo.n = 10会影响全局的foo,但foo = {n: 10}不会影响
                                                                    在声明后对变量的操作(即“var foo = {n: 2}”)不影响全局
            ②  变量为基本数据类型,值传递,局部变量使用的是全局变量,但函数执行完不会影响全局变量

发表于 2020-10-17 09:25:27 回复(0)
// 注意变量和对象属性的区别。
// 两种截然不同的情况,考的都是变量提升,也类似。
var foo = {n: 1};
(function (foo) {
    console.log(foo.n); // 1
    foo.n = 3;
    var foo = {n: 2};
    console.log(foo.n); // 2
})(foo);
console.log(foo.n); // 3

var n = 1;
(function (foo) {
    console.log(n); // undefined
    n = 3; 
    var n = 2;
    console.log(n); // 2
})(foo);
console.log(n); // 1

发表于 2017-09-05 08:19:04 回复(1)
JavaScript中 形参优先级高于声明但未赋值的局部变量; 形参优先级低于声明且赋值的局部变量。 var foo = {n:1}; (function(foo){     console.log(foo.n);//输出形参foo中n的值1     foo.n = 3;//将形参foo中n的值改为3,此时全局中的foo对象也被修改     var foo = {n:2};//为局部变量foo赋值     console.log(foo.n);//输出局部变量foo中n的值2 })(foo); console.log(foo.n);//输出全局中foo对象的n值3
发表于 2022-10-17 10:23:41 回复(0)
函数内更改会反映到全局 但是函数内重新声明会仅函数内覆盖 类似于原型链理解
发表于 2022-07-26 23:25:56 回复(0)
var foo = {n:1};
(function(foo){
   var foo; // 变量提升,因为还未赋值,固foo还是指向传入的foo
    console.log(foo.n); //  1;
    foo.n = 3;  // 修改为3,受引用类型的影响,形参传入的foo里边的n也跟着修改为3;
    foo = {n:2}; // 直接将foo 修改为 {n: 2}
    console.log(foo.n); // 所以值为 2;
})(foo);
console.log(foo.n); // 收函数体内的修改,值也为3了;
发表于 2022-03-09 13:48:30 回复(0)
我的理解思路
var foo = {n:1};
(function(foo){
    console.log(foo.n);
    foo.n = 3;
    var foo = {n:2};
    console.log(foo.n);
})(foo);
console.log(foo.n);

// 可以理解为-->

var foo = {n:1};
(function(){
    var foo // 声明形参
    var foo // 变量提升,块内foo提升,此时后声明的覆盖前声明的
    内部foo=外部foo //调用时传入的参数外部foo的引用,赋值给内部foo
    console.log(foo.n); // 输出foo.n 实际是输出外部foo的n 也就是1
    foo.n = 3; // 此时修改foo.n 按照引用的规则 其实是修改外部 foo的n 此时外部的foo={n:3}
    foo = {n:2}; // 此时为内部foo重新赋值 新的引用地址,指向{n:2}
    console.log(foo.n); // 此时输出foo.n 指向新引用地址 也就是 foo={n:2}
})(foo);
console.log(foo.n); //此处直接调用外部foo.n 它依然是3

发表于 2022-01-27 14:18:00 回复(0)
JavaScript中
形参优先级高于声明但未赋值的局部变量;
形参优先级低于声明且赋值的局部变量。
var foo = {n:1};
(function(foo){
    console.log(foo.n);//输出形参foo中n的值1
    foo.n = 3;//将形参foo中n的值改为3,此时全局中的foo对象也被修改
    var foo = {n:2};//为局部变量foo赋值
    console.log(foo.n);//输出局部变量foo中n的值2
})(foo);
console.log(foo.n);//输出全局中foo对象的n值3

发表于 2021-11-12 20:48:33 回复(0)