考题 1
难度:**
var a = 1;
function a() {}
console.log(a)
以上代码运行结果: 1
代码解析:
JS代码的运行分为 预解析阶段和执行阶段,只有在预解析结束后,才会进入执行阶段
在预解析阶段,会进行语法检查、函数及变量的声明等工作
而函数和变量的声明,是先声明函数后声明变量
解析阶段不会赋值,只会声明变量
也就是在执行前,代码中的所有函数和变量都已经声明好了,因此这种现象也叫做 声明提升
思考:下面代码的运行结果是什么?
function b() {}
console.log(b)
var b = 2;
以上代码运行结果: function b()
代码解析:
变量 b 重复声明,在第二次 var b 时,会被忽略,声明无效
-------------------------------------------------------------
考题 2
难度:***
var foo = 1;
function fn() {
foo = 10;
}
fn();
console.log(foo);
以上代码运行结果: 10
代码解析:
代码执行到 fn() 函数调用,函数中的代码就会执行
函数中 foo=10 是直接使用foo变量并赋值 而函数中并没有 foo 变量的声明
因此,根据作用域及作用域链的相关知识可知,函数中在使用变量 foo 时会向上一层作用域查找
如果找到,则直接使用,因此,全局中的 foo 变量,在函数中被重新赋值为 10
函数中 foo 也被称为 隐式全局变量
思考:下面代码的运行结果是什么?
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变量
-------------------------------------------------------------
考题 3
难度:****
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
-------------------------------------------------------------
考题 4
难度:*****
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 则是 最开始函数调用时传入的参数
最后:欢迎关注 西岭老湿 微信公众号;
欢迎关注西岭老湿知乎专栏: https://zhuanlan.zhihu.com/xilinglaoshi
西岭老湿 博客地址:http://blog.xiling.me