题目一:
(function() {
var a = b = 5;
})();
console.log(b);
控制台(console)会打印出什么?
答案:5。
这个问题的陷阱就是,在立即执行函数表达式(IIFE)中,有两个赋值,但是其中变量a使用关键词var来声明。这就意味着a是这个函数的局部变量。与此相反,b被分配给了全局作用域。
这个问题另一个陷阱就是,在函数中没有使用”严格模式” 。如果 严格模式开启,那么代码就会报错 ” Uncaught ReferenceError: b is not defined” 。请记住,如果这是预期的行为,严格模式要求你显式地引用全局作用域。
题目二:
function test() {
console.log(a);
console.log(foo());
var a = 1;
function foo() {
return 2;
}
}
test();
这段代码的执行结果是undefined 和 2。
这个结果的原因是,变量和函数都被提升(hoisted) 到了函数体的顶部。因此,当打印变量a时,它虽存在于函数体(因为a已经被声明),但仍然是undefined。
题目三:
运行以下程序,y和z的最终结果?
var m= 1, j = k = 0;
function add(n) {
return n = n+1;
}
y = add(m);
function add(n) {
return n = n + 3;
}
z = add(m);
答案:4 4
由于函数声明提升,所以函数声明会提前,由于存在同名函数,后面的add函数将覆盖第一个add函数
题目四:
以下函数运行结果为:
(function() {
var x=foo();
var foo=function foo() {
return “foobar”
};
return x;
})();
答案:TypeError: foo is not a function
foo变量“被提前”了,但是他的赋值(也就是函数)并没有被提前,从这一点上来说,和前面我们所讲的变量“被提前”是完全一致的,并且,由于“被提前”的变量的默认值是 undefined。
函数声明可以被提前,但函数表达式不能被提前
题目五:
:以下代码的输出结果是?
var f = function g() {
return 23;
};
typeof g();
答案:error
在 JS 里,声明函数只有 2 种方法:
第 1 种: function foo(){…} (函数声明)
第 2 种: var foo = function(){…}
除此之外,类似于 var foo = function bar(){…} 这样的东西统一按 2 方法处理,即在函数外部无法通过 bar 访问到函数,因为这已经变成了一个表达式。
这里如果求 typeof g ,会返回 undefined,但求的是 g(),所以会去先去调用函数 g,这里就会直接抛出异常,所以是 Error。
题目六:
var scope = "global";
function myFunc(){
console.log(scope);
var scope = "local";
}
答案:undefined
控制台打印出来的不是“global”而是“undefined”,这是因为在myFunc这个函数的作用域中,局部变量scope声明被提前至函数顶部,而此时,scope仅声明,未赋值,因此输出undefined
题目七:
var foo = 1;
function fn() {
foo = 10;
}
fn();
console.log(foo);
答案:10
代码执行到 fn() 函数调用,函数中的代码就会执行
函数中 foo=10 是直接使用foo变量并赋值 而函数中并没有 foo 变量的声明
因此,根据作用域及作用域链的相关知识可知,函数中在使用变量 foo 时会向上一层作用域查找
如果找到,则直接使用,因此,全局中的 foo 变量,在函数中被重新赋值为 10
函数中 foo 也被称为 隐式全局变量
题目八:
function fun(n, o) {
console.log(o)
return {
fun: function (m) {
return fun(m, n);
}
};
}
var a = fun(0);
a.fun(1);
a.fun(2);
a.fun(3);
答案:undefined 0 0 0
代码 var a = fun(0); 调用函数传入一个实参0,函数形参两个,因此第二形参接受到的值是 undefined
函数返回值 是一个对象 变量 a 接收
因此 a.fun() 调用的就是 对象中的fun方法
方法的返回值 是 fun() ,也就是说 a.fun(x) === fun(x,x)
参数 m 是对象方法调用时的传参,参数 n 则是 最开始函数调用时传入的参数
题目九:
var foo = 1;
function fn() {
foo = 10;
return;
function foo() {
}
}
fn();
console.log(foo);
答案: 1
在调用函数 fn 时同样会先进行预解析再进行代码执行这两个阶段
而函数中的代码在进行预解析阶段时,会先声明一个函数 foo ,此时函数内部就有了一个局部的变量声明 foo
在代码运行时,foo=10 实际是操作的函数内部的局部变量foo,而这个foo就是在预解析阶段时声明过的局部变量
所以 foo=10 不会发生作用域链的查找,因此也不会影响到全作用域中的foo变量
题目十:
var x = 1,
y = 0,
z = 0;
var add = function (x) {
return x = x + 1;
}
y = add(x);
function add(x) {
return x = x + 3;
}
z = add(x);
console.log(x, y, z);
答案:以上代码运行结果: 1 2 2
代码中有两个 add 函数,一个是表达式声明一个是关键字声明
表达式声明的函数,在预解析阶段只是声明了变量 而不是 函数
关键字声明的函数,在预解析阶段声明了函数
预解析阶段的 函数声明 要 优先于变量的声明 因此关键字函数add优先声明
但是 预解析阶段结束后,在代码执行阶段时,表达式声明的函数会被赋值
因此 两次函数的调用 y=add(x) z=add(x) 实际都是在调用 表达式函数add