首页 > 试题广场 >

在浏览器控制台中执行以下代码,输出的结果是

[单选题]
在浏览器控制台中执行以下代码,输出的结果是
function test() {
    var n = 4399;
    function add(){
        n++;
        console.log(n);
    }
    return {n:n,add:add}
}
var result = test();
var result2 = test();
result.add();
result.add();
console.log(result.n);
result2.add();


  • 4400 4401 4399 4400
  • 4400 4401 4401 4402
  • 4400 4400 4399 4400
  • 4400 4401 4399 4402
  • 4400 4401 4401 4400
推荐
这个题其实挺有难度的不知道为啥没人写解析
  • test构成了一个闭包,result跟result2各自有自己的test作用域,所以最后result2.add()结果是4400
  • 前两个没啥好说的,懵逼点在第三个,这里{n:n}是对变量n里的值进行缓存,而不是本身n这个指针变量,这样生成add的时候n指向的值是多少{n:n}里的值就是多少
写的比较简略,基础差的人很难能看懂
编辑于 2017-03-19 19:32:41 回复(67)
答案错了吧,应该是
4400 4400 4399 4401
发表于 2021-10-22 17:42:53 回复(1)
js在执行之前,会将所有带var和function的进行提前定义和声明。(带var的提前声明,function声明和定义都完成了)
首先,在全局作用域下,进行预解释:
test=xxxfff000(开辟一个堆内存,里面存的是代码字符串)
var result(声明一个变量result)
var  result2(声明一个变量result2
-------------------------------
代码执行:
result=test()  -->将test执行的返回结果赋值给result,是一个对象,再开辟一个堆内存,test执行,形成一个私有作用域A
再进行预解释和代码执行等一系列操作
result2=test()  同理
result.add()  -->方法执行形成一个私有作用域
n++  顺着作用域链向上寻找到test作用域AA这个作用域不销毁,因为被全局变量result占用了中的n为4399,n++ 》4400
(这时test这个作用域A下的n变成4400)
(1)   console.log(n)  //4400   
==============================
result.add()   -->方法执行形成一个新的私有作用域
n++  顺着作用域链向上寻找到test作用域(A)中的n为4400,n++ 》4401
(2)   console.log(n)  //4401  
===============================
(3)   console.log(result.n)  //4399
此时找的只是result对应的那个堆内存中的n
===============================
result2.add()  -->方法执行形成一个私有作用域
n++ 顺着作用域链向上寻找到test作用域(B)中的n为4399,n++ 》4400
(3)   console.log(n)  //4400 


个人理解,有哪个地方写的不对希望多多指教~~~


发表于 2017-08-03 22:04:13 回复(26)
为毛我生成的答案是这个

发表于 2017-03-24 11:16:12 回复(0)
A
发表于 2016-12-20 10:43:04 回复(2)
第十二行什么东西 ’resukt2.add();‘ 题目有问题吧
发表于 2022-03-04 11:36:14 回复(0)
什么***题目,第二个调用方法都写错了,resukt2?
发表于 2021-11-30 11:25:03 回复(0)
我他妈这里显示错的题目…result.add()resulkt2.add()console.log(result.n)result2.add()我说怎么选不出来醉了
发表于 2021-10-21 16:38:42 回复(0)

关键点:

  1. 函数每调用一次重新执行函数体中的所有代码一次,函数调用的结果是return的返回值。在本题中函数test的返回值是一个对象,每调用一次就返回一个新的对象,所以reslut1与result2是两个不同的对象。
  2. 对象的属性和方法只有该对象自己能够使用,对象内部的方法不能够通过属性名或者方法名来使用同一对象内部的其它属性值或者方法。图片说明
    图片说明
    因此,前面reslut.add()对reslut指向的对象里面的属性'n:4399'没有影响
发表于 2018-08-25 17:30:10 回复(0)
http://www.ruanyifeng.com/blog/2009/08/learning_javascript_closures.html  闭包
发表于 2017-04-09 16:58:25 回复(0)
这个可以吧,函数内的改变与外界无关,函数内定义变量,外面是无法调用的,return,是返回了一个对象的引用,直接改变,则return中的值改变,在函数中改变,不会改变,增加一个:

发表于 2017-04-07 14:30:53 回复(1)
这里一共才输出4次?
发表于 2017-04-03 22:30:29 回复(0)
纯属娱乐解法:以概率来解,第一项不用看了,都一样,从第二个看可以排除C,从第三个看可以排除B,E,从第四个看可以排除D,答案选A
发表于 2017-03-13 21:20:31 回复(2)
function test(){
	var n = 4399;
	function add(){
		n++;//注意这里的n是上面的'var n = 4399'
		console.log(n);
	}
	return {
		n: n,
		add: add
	}
}

发表于 2016-12-28 10:54:38 回复(0)
首先,题中定义了一个函数,名为test,这个函数内部分别又定义了一个数值变量n和一个闭包函数add,test函数的最后一行代码return{n:n,add:add},实际上是返回了一个object,而这个object中有一个属性n,它的值是n,还有一个方法add,它的值是add。
好了,函数解释清楚,再来看输出的问题。函数外部分别定义了两个变量,result和result2,他们都指向test函数,但是分属两个不同的作用域,这也就解释了答案中1和4,4不会在2的基础上继续n++。
1和2属于闭包函数的问题,可参考阮一峰老师的一篇博文(http://www.ruanyifeng.com/blog/2009/08/learning_javascript_closures.html),简单易懂,借用阮老师博客中所写,闭包的两个最大的用处:一个是可以读取到函数内部的变量,另一个就是让这些变量的值始终保持在内存中,具体可以测试。第二个用途就解释了同一个作用域中答案2会在1的基础上进行+1操作。
答案3是比较令人困惑的一项,追本溯源,前面提到过第6行代码返回了一个有着值为n的属性n和值为add的方法add的匿名对象,在这里,在这个匿名对象中,属性n和方法add是互不相关的,即使在闭包add中改变了变量n的值,result.n的值依然不变。
以上,首答,说了下自己的理解,有不对的地方还望指正。

发表于 2017-04-27 22:03:06 回复(15)
发表于 2017-07-05 20:31:13 回复(9)
var result = test(); 这句话执行之后,result 指向一个对象:
{
    n: 4399,
    add: function() {
         n++;
         console.log(n);  //此 n 不是彼 n
    }
}
注意了!!!注意了!!!,这个add函数中的n不是这个对象的n,而是指向原函数 test 中的n,为什么?因为闭包啊,你把 test 函数中的 add 函数返回到全局作用域了(变量result),根据作用域链,函数的能够访问到的参数和变量是声明时决定的,所以当你执行 add 函数的时候,其实是回到了 test 函数中,把 test 函数中 n 进行加一操作。而不是把 result 对象的 n 属性值加一,result 中 n 早已经赋值为 4399了。 所以,答案中 第三个 蜜汁 4399 就是这么来的。
发表于 2017-07-20 14:52:23 回复(9)

test 构成了一个闭包, result result2 各自有自己的 test 作用域,所以最后 result2.add() 结果是 4400

var result=test();   // 执行 test 返回 {n:4399,add:add};

var result2=test();   // 同理,执行 test 返回 {n:4399,add:add};

result.add();

//test 构成闭包, add 作用域链包含 test 活动对象,所以 n++ ,会调用 test 活动对象的 n 累加,得到 4400

result.add();  // 和前面指向同一个 result 对象,所以不会初始化而是继续加 1 ,为 4001

console.log(result.n);  //{n:4399,add:add}; 无关 add

result2.add();  // 作用域链有 test 活动对象,但是这个跟 result 的不是同一个。 4399+1= 4400

不同对象的闭包是彼此独立的,不相互影响。欢迎指正。

发表于 2017-04-14 14:45:23 回复(5)
题目打错了就算了,答案也没个对的。
想了半天都开始怀疑自己了。
出题的还能不能行了😅😅😅
发表于 2021-10-23 15:05:50 回复(8)
add方法在return的适时候就形成了一个闭包,包含n=4399这个值,这个n不是result和result2里的属性值n。两个不同对象的闭包是彼此独立的,不互相影响。
发表于 2017-01-17 15:45:16 回复(3)
从内存说起。
基本数据类型(String,Number,Boolean,Undefined,Null)进行复制的时候,在栈中创建一个新变量,再将值赋给这个新变量;
引用数据类型(Object,数组,函数)复制的时候,在栈中创建一个新变量,再将引用数据类型的堆地址赋值给这个新变量,也就是说这个地址副本和原地址指向的是同一个数据类型。

题目中,test函数返回的{n:n,add:add}中,n是新创建的变量,add是原函数的引用。
执行两次test函数后会生成 两个 不会互相干预的对象。
执行result.add时,相当于执行test()函数中的add(),而add()中有未声明的变量n,程序会解析add的作用域链(这里形成了闭包),向上寻找一个作用域环境,找到test()的环境中的n。最后执行的部分就很简单了。
所以,result.n所代表的的n与result.add()输出的n不是同一个n,第三个是不会变的4399

发表于 2017-07-14 16:40:28 回复(5)