js高级笔试必会题

1. var name = 'World!';
(function () {
if (typeof name === 'undefined') {
var name = 'Jack';
console.log('Goodbye ' + name);
} else {
console.log('Hello ' + name);
}
})();

2.var a = 10;
function fn(){
console.log(a);
}

function bar(f){
var a = 20;
f();
}
bar(fn);

3.function sidEffecting(ary) {
ary[0] = ary[2];
}
function bar(a,b,c) {
c = 10
sidEffecting(arguments);
return a + b + c;
}
bar(1,1,1)
结果是 21, 在javascript的变量中 arguments 是个对象,
所以arguments 和局部变量所引用的内容是一样的。

4.function say666(){
var num = 666;
var sayAlert = function() {
alert(num);
}
num++;
return sayAlert;
}
var sayAlert = say666();
sayAlert()
执行say666()后,say666()闭包内部变量会存在,而闭包内部函数的内部变量不会存在
使得Javascript的垃圾回收机制GC不会收回say666()所占用的资源。
因为say666()的内部函数的执行需要依赖say666()中的变量。

5.function f1(){
    var n=999;
    nAdd=function(){n+=1}
    function f2(){
      alert(n);
    }
    return f2;
  }
  var result=f1();
  result(); // 999
  nAdd();
  result(); // 1000
首先要说的是,闭包是functional language里面的核心概念。
当出现高阶嵌套函数的时候,编译器会做closure convention闭包变换,核心就是变量不在分配在stack上,而是分配在heap上。这就是为什么f1已经返回,但是n还能被+1的原因。
楼主给出的这个程序,实际上就是一个高阶嵌套函数。
1. 因为在函数里面有定义的函数,这是嵌套。pascal也是允许嵌套函数。
2. 高阶的原因是,函数可以所谓参数传递和返回,像我们熟悉的C语言。
但是当高阶和嵌套同时出现,就会造成麻烦,所以pascal和C都只能支持其中的一个。
我来分析一下这个程序的执行流。
1. var result=f1(); 返回了一个函数f2, 因此result为f2。这个高阶函数特性,参考C语言函数指针。
2. result(); 调用f2,显然输出999.
3. nAdd(); 这里需要注意,这个nAdd实际上在定义的时候是一个lambda,是一个匿名函数,功能是n+=1。定义时将这个函数赋值给nAdd。所以在此时,实际上是调用了n+=1.为什么能找到n?因为n在堆里面。
4. result(); 调用f2,显然输出1000.
最后一点,n在堆上如何被销毁,这个工作是垃圾收集器负责。当n不在被任何闭包的env引用的时候,会被回收。
function f1(){
    var n=999;
    function f2(){
      alert(n);
    }
    nAdd=function(){n+=1}
    return f2;
  }
  var result=f1();
  result(); // 999
  nAdd();
  result(); // 1000
var result=f1():f1函数返回了f2函数
把返回的f2函数赋值给result全局变量,(f2的作用域链保存到result全局变量中)
result():调用result(),这就形成闭包:有权访问另外一个函数作用域中的变量
因为在f2中的作用域引用了f1中的n这个局部变量,当f1执行完毕后,垃圾回收机制发现n变量还在被result中引用所以垃圾回收机制不会把n回收释放。
以至于n一直保存在result作用域链中。result的作用域链正常能访问f1中的局部变量n,形成闭包。
nAdd():nAdd没有写var所以nAdd是全局变量,在调用nAdd()和result()是一样的都会形成闭包,匿名函数function(){n+=1}的作用域链中有n这个局部变量,所以当nAdd=funtion(){n+=1}时,这个匿名函数的作用域链保存到了全局变量nAdd形成闭包,调用nAdd()作用域链中找到f1局部变量n=999,n+1=1000。
result():result()就输出1000
nAdd();重复第三步骤 n+1 = 1001
result();重复第四步骤 输出n
f1();调用f1时并没有形成闭包,n永远都是999,因为每次f1执行结束后n都被垃圾回收机制销毁了,所以这里再次调用 var n=999;后面输出也都是999
为什么 nAdd 的表达式会影响到 f2 的 n?
因为闭包的原因n一直都没被销毁,nAdd()也形成了闭包,并改变了n的值,所以后面再次调用result() n没被销毁回收一直被+1,所以会被影响。
最后在调用f1()时没有闭包,之前n是被销毁了。所以一直输出a=999;

6.function fun(n,e) {
console.log(e)
return {
fun:function(m){
return fun(m,n);
}
};
}
var a = fun(0); a.fun(1); a.fun(2); a.fun(3);//undefined,?,?,?
var b = fun(0).fun(1).fun(2).fun(3);//undefined,?,?,?
var c = fun(0).fun(1); c.fun(2); c.fun(3);//undefined,?,?,?
//问:三行a,b,c的输出分别是什么?
//答案:
//a: undefined,0,0,0
//b: undefined,0,1,2
//c: undefined,0,1,1
先看第一个fun函数,属于标准具名函数声明,是新创建的函数,他的返回值是一个对象字面量表达式,属于一个新的object。
这个新的对象内部包含一个也叫fun的属性,通过上述介绍可得知,属于匿名函数表达式,即fun这个属性中存放的是一个新创建匿名函数表达式。
注意:所有声明的匿名函数都是一个新函数。
所以第一个fun函数与第二个fun函数不相同,均为新创建的函数。

猜你喜欢

转载自www.cnblogs.com/wangpenglei/p/9595500.html