美文网首页每日一题Web前端之路让前端飞
第11题- 变量提升和函数提升

第11题- 变量提升和函数提升

作者: 青天诀 | 来源:发表于2019-08-23 00:56 被阅读0次

面试题目(腾讯):

下面题目输出结果是什么?

var a=2;
function a() {
    console.log(3);
}
console.log(typeof a);

答案解析:

这道题目主要考察JS的变量提升和函数提升相关的知识点

1. 变量提升

ES6之前,JavaScript没有块级作用域(一对花括号{}即为一个块级作用域),只有全局作用域和函数作用域。变量提升即将变量声明提升到它所在作用域的最开始的部分。下面两个示例包含了变量提升的两种情况(全局作用域和函数作用域):

示例 1

console.log(a);
var a = 8;

// 变量提升后等价于下面代码
var a;
console.log(a) // undefined
a = 8;

示例 2

var a = 8;
function fn() {
    console.log(a);
    var a = 9;
    console.log(a);
}

// 变量提升后等价于下面代码

var a = 8;
function fn() {
    var a;
    console.log(a);
    a = 9;
    console.log(a);
}

2. 函数提升

js中创建函数有两种方式:函数声明式和函数字面量式。只有函数声明才存在函数提升

示例

console.log(f1);  
console.log(f2);  
function f1() {}
var f2 = function() {}

// 函数提升后等价于下面代码

function f1() {}
var fn;
console.log(f1); // function f1() {}   
console.log(f2); // undefined  
f2 = function() {}

3. 变量提升 VS 函数提升

上面的面试题目就属于这种类型,变量和函数同名。当两种提升都存在的情况下,结果是什么样的呢?

var a=2;
function a() {
    console.log(3);
}
console.log(typeof a);

// 变量提升和函数提升后,代码变为

function a() {
    console.log(3);
}
a=2;
console.log(typeof a); // number

为什么是这样呢?这就需要从JS的编译过程解释了。

在JS代码执行前,会执行词法分析。所以JS运行要分为词法分析和执行两个阶段。

函数在运行的瞬间,会生成一个活动对象Active Object,简称AO

  1. 分析形参
    1. 如果函数有形参,则给当前活动对象增加属性,赋值为undefined
  2. 分析变量
    1. 如果AO上还没有 XXX 属性,则给当前活动对象增加属性,赋值为undefined.
    2. 如果AO上有 XXX 属性,则不做任何影响。
  3. 分析函数
    1. 把函数赋值给 AO.func 属性
    2. 如果此前 func 属性已存在,则覆盖。(证明函数的优先级比较高)

面试题目分析系过程大致如下:

  1. 分析形参
    • 因为是全局环境,可以理解为自执行函数,没有形参。
  2. 分析变量
    • 按照2.1的规则,AO.a = undefined
  3. 分析函数
    • 按照3.2的规则直接覆盖掉a属性,AO.a = function(){console.log(3)}

4. 为什么会有提升

Brendan Eich给出了答案:

  1. 由于第一代JS虚拟机中的抽象纰漏导致的,编译器将变量放到了栈槽内并编入索引,然后在(当前作用域的)入口处将变量名绑定到了栈槽内的变量。(注:这里提到的抽象是计算机术语,是对内部发生的更加复杂的事情的一种简化。)
  2. 函数提升就是为了解决相互递归的问题,大体上可以解决像ML语言这样自下而上的顺序问题。

总体意思就是:变量提升是人为实现的问题,而函数提升在当初设计时是有目的的。

补充:

js中无论哪种形式声明(var,let,const,function,function*,class)都会存在提升现象,不同的是, var,function,function*的声明会在提升时进行初始化赋值为 undefined,因此访问这些变量的时候,不会报ReferenceError异常,而使用 let,const,class 声明的变量,被提升后不会被初始化,这些变量所处的状态被称为“temporal dead zone”,此时如果访问这些变量会抛出ReferenceError异常,看上去就像没被提升一样。

总结:

  1. js会将变量的声明提升到js顶部执行,因此对于这种语句:var a = 2;其实上js会将其分为var a;a = 2;两部分,并且将var a这一步提升到顶部执行。
  2. 变量提升的本质其实是由于js引擎在编译的时候,就将所有的变量声明了,因此在执行的时候,所有的变量都已经完成声明。
  3. 当有多个同名变量声明的时候,函数声明会覆盖其他的声明。如果有多个函数声明,则是由最后的一个函数声明覆盖之前所有的声明。

扫一扫 关注我的公众号【前端名狮】,更多精彩内容陪伴你!

【前端名狮】

相关文章

  • 第11题- 变量提升和函数提升

    面试题目(腾讯): 下面题目输出结果是什么? 答案解析: 这道题目主要考察JS的变量提升和函数提升相关的知识点 1...

  • JS中的提升

    JS中包含两种提升,变量提升和函数提升。 变量提升 变量提升只能是var或者function声明的变量或者函数,l...

  • JavaScript中函数声明提升

    运行结果:(chrome 54.0+、IE11) js中变量声明和函数声明会在解析的时候提升【参考MDN变量提升】...

  • 引用类型

    变量提升和函数声明提升   函数声明提升就是把函数声明提升到函数声明所在作用域中(或者说一个函数体内)的顶端,变量...

  • 2021-04-02

    变量提升和函数提升以及他们的优先级 1,变量提升:变量提升是指将变量声明提升到它所在的作用域的最开始部分 2,函数...

  • 关于变量提升

    函数提升的优先级要高于变量提升,变量提升到函数声明的后面; 变量提升,但是赋值不提升,函数表达式不提升;

  • let const var

    变量提升 函数会优先于变量提升; 函数提升会把整个函数移到作用域顶部 变量提升智慧把变量的定义移到作用域顶部 wi...

  • 变量提升

    变量提升 Hoisting 变量和函数的声明会在编译时被提升到作用域的顶部 提升的是声明,函数会连带函数体提升 i...

  • 变量提升和函数提升

    摘自《你不知道的JavaScript上卷》KYLE SIMPSON著 变量提升 引擎会在解释 JavaScript...

  • 变量提升和函数提升

    1.变量提升 console.log(a);//undefined var a=123; 因为变量a的声明被提到了...

网友评论

    本文标题:第11题- 变量提升和函数提升

    本文链接:https://www.haomeiwen.com/subject/jbmasctx.html