JS预解析时变量提升、函数提升及函数实参传值先后问题

326 阅读2分钟

JS预解析时变量提升、函数提升、函数实参传值的先后问题

一、全局作用域内

在全局作用域内有这样几句代码,我们来思考一下其执行结果。

<script>
  console.log(f);
  function f() {};
  var f = 3;
</script>

代码的顺序是先函数声明后变量声明,如果函数提升和变量提升的优先级一样,相当于执行了如下代码:

var f = function f() {};
var f = undefined;
console.log(f); //结果为undefined
f = 3;

如果函数提升在变量提升之前,相当于执行:

var f = function f() {};
var f = undefined;
console.log(f); //结果为undefined
f = 3;

如果函数提升在变量提升之后,相当于执行:

var f = undefined;
var f = function f() {};
console.log(f); //结果为function f() {}
f = 3;

而实际上的输出结果为:function f() {}

这说明了:在预解析时,函数提升是在变量提升之后,函数提升的值会覆盖之前的变量提升的值。

二、函数作用域内

  1. 第一段代码:
<script>
  function f(a) {
    console.log(a);
    var a = 2;
  }
  f(1);
</script>

其输出结果为传入的实参的值1,这个答案貌似显而易见,不过这其实说明了一个信息:函数内,变量提升在前,实参赋值在后。

上面代码等价于:

<script>
  function f(a) {
    var a = undefined;
    a = 1;
    console.log(a);
    a = 2;
  }
  f(1);
</script>
  1. 第二段代码
<script>
  function f(a) {
    console.log(a);
    function a() {};
  }
  f(1);
</script>

其输出结果为:function a() {},这说明:实参赋值在前,函数提升在后。

所以能得出结论:函数内的预解析流程是,先变量提升,再进行实参给形参赋值,最后函数提升,后面的值会覆盖前面的值。

测试题(来自于B站UP主:程序员有道)

function fn(a, c) {
    console.log(a); 
    var a = 123;
    console.log(a); 
    console.log(c); 
    function a() {};
    
    if (false) {
        var d = 678;
      };
    console.log(d); 
    console.log(b); 
    var b = function () {};
    console.log(b); 
    function c() {};
    console.log(c); 
  }
  fn(1, 2);
分析:

函数调用后,在开始执行函数内的代码前会进行预解析,函数内的预解析流程是:1. 变量提升;2. 实参给形参赋值;3. 函数提升。

现在就以这个流程来分析这道题。

  1. 变量提升阶段(有声明变量的地方就会有变量提升)
var a = undefined; //var a = 123;
var b = undefined; //var b = function () {};为变量声明,非函数声明
var d = undefined; //var d = 678;
  1. 实参给形参赋值
a = 1;
var c = 2;
  1. 函数提升
a = function a() {}; //function a() {};
c = function c() {}; //function c() {};

所以预解析后的结果为:

a = function a() {};
b = undefined;
c = function c() {};
d = undefined;

所以该测试代码等价于:

var a = function a() {};
var b = undefined;
var c = function c() {};
var d = undefined;
console.log(a); //输出function a() {}
a = 123;
console.log(a); //输出123
console.log(c); //输出function c() {}
    
if (false) {
    d = 678;
};
console.log(d); //输出undefined
console.log(b); //输出undefined
b = function () {};
console.log(b); //输出function () {}
console.log(c); //输出function c() {}