前端面试系列-JavaScript-变量提升、预编译(附面试题)

js预编译

js执行前会进行预编译。
会产生一个 GO ,也就是我们说的全局作用域 , 当一个方法被调用时会形成一个局部作用域 AO。

全局代码在执行的时候,先是 变量提升 , 在全局作用域内添加 属性,然后是 函数(以函数声明创建的函数)提升,再是代码执行。

1.全局预编译GO(Global Object)

  1. 创建GO对象,即window
  2. 给全局变量赋值 undefined
  3. 将全局的函数申明的函数名作为key,value为函数整体赋值到GO对象中

2.函数预编译AO (Activation Object)

  1. 创建AO对象
  2. 将函数内的形参和变量声明存储到AO对象中,值为undefined
  3. 将实参和形参统一
  4. 将函数内的函数申明的名称作为AO对象的key,函数的整体内容为value 存储到AO对象

来个例子:

 function f(a){
      console.log(a);
      var a=123;
      console.log(a);
      function a(){}
      var b=function(){}
      function d(){}
  }
  f(1)
 //ƒ a(){}
//123

代码分析:

  1. 创建AO对象
AO={}
  1. 找形参和变量声明,将变量和形参名作为AO属性名,值为undefined
AO={
    a:undefined,
    b:undefined
}
  1. 将实参值和形参统一
AO={
    a:1,
    b:undefined
}
  1. 在函数体里面找函数声明,值赋予函数体:由于在函数中有 function a() {} ,这一函数因此此时AO中 a = function a() {}
AO={
 a:function a(){},
 b:undefined,
 d:function d(){}
}

然后代码依次执行,第一个console时取AO中的a为function a(){},然后a=123,改变AO中的a为123

AO={
 a:123,
 b:undefined,
 d:function d(){}
}

接着打印a为123

3.预编译小结

  • 函数声明整体提升-(具体点说,无论函数调用和声明的位置是前是后,系统总会把函数声明移到调用前面)
  • 变量声明提升-(具体点说,无论变量调用和声明的位置是前是后,系统总会把声明移到调用前,注意仅仅只是声明,所以值是undefined)
  • 任何变量,如果未经声明就赋值,则此变量就位全局变量所有。(全局域就是Window)
  • 一切声明的全局变量,全是window的属性; var a = 12;等同于Window.a = 12;
  • 函数预编译发生在函数执行前一刻。

变量提升

根据上文所提到的,变量提升:在预编译的时候会将函数内变量声明存储到AO对象中,值为undefined

console.log(name)   // 'undefined'
var name = 'John Doe'
console.log(name)   // John Doe

let & const提升

console.log(a)  // ReferenceError: a is not defined
let a = 3

function, var, let, const, class 都会被“提升”。但是let和const声明的变量不会被初始化值为undefined,
只有在执行阶段JavaScript引擎在遇到他们的词法绑定(赋值)时,他们才会被初始化。这意味着在JavaScript引擎在声明变量之前,无法访问该变量。

let a
console.log(a)  // undefined
a = 5

class提升

同let和const一样,class在JavaScript中也是会被“提升”的,在被真正赋值之前都不会被初始化值。

let peter = new Person('John', 25) // ReferenceError: Person is not defined
class Person {
  constructor(name, age) {
    this.name = name;
    this.age = age;
  }
}
let John = new Person('Tom', 18); 
console.log(John) // Person { name: 'Tom', age: 18 }

练习题

helloWorld();  // TypeError: helloWorld is not a function
var helloWorld = function(){
  console.log('Hello World!');
}
//Uncaught TypeError: helloWorld is not a function
helloWorld();
function helloWorld(){
  console.log('Hello World!');
}
//Hello World!
foo();
var foo; 
function foo(){
    console.log('tom');
}
foo = function(){
    console.log('jack');
}
//tom

面试真题

var name = 'Tom';
(function() {
if (typeof name == 'undefined') {
  var name = 'Jack';
  console.log('Goodbye ' + name);
} else {
  console.log('Hello ' + name);
}
})();
//Goodbye Jack

变形一

var name = 'Tom';
(function(name) {
if (typeof name == 'undefined') {
        var name = 'Jack';
        console.log('Goodbye ' + name);
    } else {
        console.log('Hello ' + name);
    }
})(name);
//Hello Tom

变形二

var name = 'Tom';
(function() {
if (typeof name == 'undefined') {
        let name = 'Jack';
        console.log('Goodbye ' + name);
    } else {
        console.log('Hello ' + name);
    }
})();
//Hello Tom

本文链接:https://blog.csdn.net/qq_39903567/article/details/115080104

猜你喜欢

转载自blog.csdn.net/qq_39903567/article/details/115080104