有一次去面试的时候,遇到这么一个看上去非常简单明了的题目,但答案却又不明觉厉!
console.log(a);
console.log(f);
var a = 2;
function f(a){
a = 3;
}
f(a);
console.log(a);
console.log(f);
乍一看很明了,“简单”的我都怀疑自己的答案了,然而确实不用怀疑,自己的答案就是错的!正确的输出结果是这样的:
console.log(a); //undefined
console.log(f); //f(a){a = 3}
var a = 2;
function f(a){
a = 3;
}
f(a);
console.log(a); //2
console.log(f); //f(a){a = 3}
那就一行一行的解释以下
- 第一行:“a”没有声明为什么不报错?
原来JS有一个变量声明提前的机制,var 定义变量的时候,js是首先直接把变量声明到作用域的最顶部的,所以这个时候,全局都能找到这个变量,所以在定义之前调用这个变量,是不会报错的。
下面左右两边的代码是完全一样:
console.log(a); var a;
=== console.log(a);
var a = 2; a = 2;
当然这只局限于var声明,如果用let声明就不行了,就会报错!
- 接着第二行为什么函数f()没有声明却还能输出值?
与变量声明提前一样,函数也有个神经机制,就是函数声明提前,但与变量不一样的是,函数提前的是函数体,也就是说,在作用于范围内,只有又函数,不管函数体写在哪儿,同意上升到作用域最顶端!
上代码,左右两边全等于
console.log(f); function f(a){
function f(a){ === a = 2;
a = 2; }
} console.log(f);
- 第三次输出为什么a的值没有改变?
因为JS的函数是值传递,上述代码并没有把"a"这个变量传到函数中,而是把"2"这个值传过去了,所以函数中如何对这个值修改都不会影响到变量"a"
- 如果用同一个变量名来声明函数和变量,该是什么情况?
console.log(a);
var a = 2;
function a(){
console.log("bazinga");
}
这里又要说到JS的另一个规定,函数会首先被提升,然后才是变量。也就是说,同一作用域下提前,函数会在更前面。以上代等同于:
function a(){
console.log("bazinga"); // bazinga
}
var a; //重复声明且未改变对象值,这一行直接被忽略
console.log(a); //输出函数体
a = 2;