1、变量提升和函数提升

function b(){
  console.log(a);
  var a = 10;
  function a(){}
  a = 100;
  console.log(a);
}

b(); // function(){}, 100

解析:

执行第一句console.log(a)时,同时声明了函数a和变量a,根据规则,变量a的声明被忽略,所以打印出function;
执行第二句console.log(a)时,a已经被重新赋值为100。

扩展:

函数提升和变量提升规则:
同名的变量,后声明的会被忽略,同时只有声明被提升,也就是此时变量的值是undefined;
同名的函数,后声明的会覆盖先声明的;
同名的函数和变量,变量声明被忽略

2、变量作用域和上下文

var num = 10;
var obj = {
  num: 8,
  inner: {
    num: 6,
    print: function(){
      console.log("num: " + num + ", this.num: " + this.num);
    }
  }
}
num = 888;

下面语句输出什么?
1、obj.inner.print();
2、var fn = obj.inner.print;
   fn();
3、(obj.inner.print)();
4、(obj.inner.print = obj.inner.print)();

解析:

1、888, 6
首先根据[作用域链]查找num。在print函数中没有定义num,就会向上一级查找,此时的作用域链只有两层:顶层的window和print,所以就会找到全局变量num,也就是window.num,此时num等于888。
其次查找this.num。此时this指向obj.inner,obj.inner.num = 6。

2、888, 888
在JavaScript中,函数是是引用类型,所以此语句相当于让fn指向obj.inner.print的地址。此时调用fn是在window下,所以输出两次888。

3、888, 6
4、888, 888
()是表达式,(obj.inner.print)等于obj.inner.print,这和第四问中不同,第4问括号中存在一个赋值语句,赋值语句有返回值,等于等号右侧的计算结果。在这里,这个返回值是obj.inner.print的地址,相当于在当前window环境中调用这个地址的函数,所以情况就变得和第2问一样了。

标签: JavaScript面试题, 作用域链, 变量提升, 函数提升