美文网首页前端开发『巨坑』系列教程
前端开发『巨坑』系列—变量提升详解

前端开发『巨坑』系列—变量提升详解

作者: 党云龙 | 来源:发表于2019-12-20 21:56 被阅读0次

前言


在经过了一轮面试挫败以后,我发现了一个问题:
通常大公司对你的底层基本功非常感兴趣,他们根本不在乎你能够使用多少个前端框架。因为真正的好公司都是自己开发框架的。

今天我们要像discovery节目一样深入前端开发底层的知识,揭露js es5中那些常见的疑难杂症以及解决办法。让你搞清楚为什么这些大厂喜欢考你这些问题,然而这些问题背后又隐藏了什么历史巨坑,让龙哥给你层层揭开真相!

历史谜案!变量提升


不知道你又没有发现,在js中var是一个非常有意思的关键字。
有意思到,它根本都不按照编程语言的逻辑去执行—从上到下执行。什么意思,我TM还没有声明这个变量的时候,我居然就可以用了。

console.log(name); //dangyunlong
var name = "dangyunlong"

这是非常残酷的一个事实。说明es5中通过var来声明变量,这个变量无论在当前作用域的什么位置,它都会被提到作用域的最顶部。

console.log(name);//报错
let name = 1;
console.log(name);//1

当然,这个问题在es6中已经通过let关键字,解决了。

那么,仅仅就这样而已吗?当然不是!

我们再更进一步,把这个例子写的稍微复杂一点,给它增加一个作用域。

var name = 2;
(function(){
    console.log(name);//2
})()

首先我们普及两个知识点:

1.js中没有块作用域,只有全局和函数作用域。
2.自执行匿名函数,也叫做立即执行函数,无论你写在页面的任何位置,它都会先于所有代码执行。

ok,然后我们再回来看这个例子。自执行匿名函数先于代码执行,可是,var的name还是存在。这说明var的权限是更高,这里打印出来的是全局的name。

懵逼的开始!


看完了上面的例子,咱们再来看这个:

(function(){
    console.log(num);//undefined
    var num = 1;
})()

这里你感觉num应该打印出来1吗,那你就错了,这里打印出来undefined。

但是我们上面说,var出来的值,再任何位置都可以用啊?为什么在函数体中不能先使用再声明呢?

龙哥猜测,这可能跟我们在函数体内声明变量,该变量成为局部变量有关系,

(function(){
    console.log(num);//undefined
    var num = 1;
    console.log(num);//1
})()

放到下面就可以打印出来了。

来道面试题做做

var name = "tom";
(function(){
    if(typeof name==="undefined"){
        name = "jack";
        console.log("goodbye"+name);
    }else{
        console.log("hello"+name);
    }
})()

这道题应该打印什么?
看过前面的例子我们就知道了,应该打印hello tom。

我们来解释一下,首先,全局里面有var的变量,全局的肯定最大,无论在哪都能访问到。所以typeof name肯定就不是undefined。于是就进入了判断的else环节,所以打印出来hello tom。

然后龙哥把这道题升级了:

var name = "dangyunlong";
(function(){
    console.log(name); //第一个
    var name = "lilei";
    name = "gaoyuanyuan"
})()
console.log(name); //第二个

function fun(){
    name = "shiliujie"
}
fun();
console.log(name); //第三个

请问这三个console.log分别打印什么。

解:
1.第一个我们跟前面一题的道理一样,打印undefined。
2.第二个打印dangyunlong。有的同学可能会问,第二个不是打印gaoyuanyuan吗?注意,如果没有它上面的var name = “lilei”它确实会打印gaoyuanyuan。但是有了var,表示当前的name已经指函数体的局部变量name了,而不是全局那个。
3.第三个打印shiliujie。道理跟第二个一样,因为这次函数体内修改的是全局变量的值,并没有声明局部变量!

历史谜案!函数声明提升!


先来补充一个小知识:
什么是函数声明和函数表达式。

//函数表达式
var fun1 = function(){
    console.log("我是fun1");
}

//函数声明
function fun2(){
    console.log("我是fun2");
}

来看这俩哥们。

咱们也不卖关子了,这俩在执行上面没有任何区别。是一模一样的。

那么问题就来了,难道这个也存在提升的问题吗?是的。

//函数表达式
var fun1 = function(){
    console.log("我是fun1");
}
fun1(); //我是fun1

//函数声明
function fun2(){
    console.log("我是fun2");
}
fun2(); //我是fun2

这样运行是没问题的,但是,请看这种写法:

fun1(); //fun1 is not a function
//函数表达式
var fun1 = function(){
    console.log("我是fun1");
}

fun2(); //我是fun2
//函数声明
function fun2(){
    console.log("我是fun2");
}

函数表达式直接报错,但是,函数声明可以运行。

这TM就太厉害了。我们使用var的关键字出来的函数没有被提升,但是直接function却提升了,这是怎么回事?

其实这里面有一个误区,就是除了变量会提升以外,函数也会被提升。

如果我们直接声明一个函数,他也一样会提升到顶部。但是,如果我们以变量形式声明一个函数表达式,它其实走的是变量提升:

fun1(); //fun1 is not a function
//函数表达式
var fun1 = function(){
    console.log("我是fun1");
}

//执行顺序
var fun1;
fun1();
fun1 = function(){
    console.log("我是fun1");
}

这样的话,会报fun1不是function,因为变量提上去了以后,变量并没有被赋值。然后我们又执行了fun1();
所以这里就直接报错了。fun1这时候还不是函数,所以肯定是报这个错误了。

最后总结


所以龙哥帮大家总结除了以下结论,以后再做题的时候,一定要注意:

1.如果题中有函数,先看是否在函数内部使用了var。如果使用了,这里面的赋值就是指局部变量。局部变量没有提升的问题,如果先打印,会报undefined。
2.函数中没有var直接赋值的,修改的是全局的值。
3.全局变量无论在什么地方声明,都会提升到作用域的顶部。所以即使在开头就打印,打印出来的也是var的值。
4.函数声明有提升的问题,函数表达式走的是变量提升,所以提前运行会报这个方法不是一个function。

到此,提升问题全部浮出水面,最好的解决办法当然是通过let。这个提升的问题一定要注意,否则很有可能你无意之中修改了全局数据,导致溢出污染。

相关文章

  • 前端开发『巨坑』系列—变量提升详解

    前言 在经过了一轮面试挫败以后,我发现了一个问题:通常大公司对你的底层基本功非常感兴趣,他们根本不在乎你能够使用多...

  • 前端开发『巨坑』系列—类数组详解

    这个数据好像不是数组 当后台给我们传递了一个数组,我们正好来一个v-for美滋滋循环的时候。突然之间就报错了。循环...

  • web前端入坑第四篇:你还在用 jQuery?

    先来补齐【web前端入坑系列】前三篇的连接web前端入坑系列:点击标题进入第一篇: web 前端入坑第一篇:web...

  • 前端变量提升

    仅供参考20/37/48/9/46/40 今天和大家分享下变量的提升问题 JavaScript 中,函数及变量的声...

  • 变量提升详解

    自认为对变量提升有一定的了解,其实不然。 概念 什么是变量提升 变量提升,在当前上下文中(全局/私有/块级),js...

  • 前端基础进阶系列

    前端基础进阶(一):内存空间详细图解前端基础进阶(二):执行上下文详细图解前端基础进阶(三):变量对象详解前端基础...

  • iOS开发技巧系列---详解KVC(我告诉你KVC的一切)

    iOS开发技巧系列---详解KVC(我告诉你KVC的一切) iOS开发技巧系列---详解KVC(我告诉你KVC的一切)

  • IOS学习(13)-UITextView

    UITextView详解iOS开发系列之四 – UITextView 用法小结UITextView控件的用法详解

  • 移动前端开发规范(一般规范)

    系列目录 移动前端开发规范(一般规范)移动前端开发规范(技术栈规范)移动前端开发规范(HTML规范)移动前端开发规...

  • 前端框架设计学习笔记一

    把前端开发当作“一个值得作出战略规划和有投资价值的关键元素”。 前端架构是一系列工具和流程的集合,旨在提升前端代码...

网友评论

    本文标题:前端开发『巨坑』系列—变量提升详解

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