《前端实战总结》之变量提升,函数声明提升及变量作用域详解

徐小夕 等级 601 0 0

之所以会写这篇文章,主要源于笔者在重构老项目的时候发现了一个bug,导致某个插件不生效了,在review加search code加断点调试之后,发现了原因:一个同名的变量将插件方法给覆盖了,ohmyGad。

正文

1.变量是如何被覆盖的

在一般情况下,js代码都是自上而下执行的,对于同一个变量,我们可以通过如下方式来修改:

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

2.变量提升

上面的覆盖过程大家都很好理解,那么看如下的操作呢?

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

这个时候console.log()都会输出undefined而不会报错,这是为什么呢?这里就是变量提升起到的作用。我们在用var或者函数声明的方式定义一个变量时,这个变量的定义会提升到方法体的最顶端,即如下所示:

var a = undefined;
var b = undefined;
console.log(a)
// ..
console.log(b)

因此我们得出一条结论:

函数声明和变量声明总是会被解释器悄悄地被"提升"到方法体的最顶部。

值得注意的是,我们使用let,const定义变量的时候,并不会发生提升,因为它存在局部(块)作用域的概念,会出现暂时性死区,所以在它们之前打印变量将报错。如果对暂时性死区或者对es6不太了解的朋友可以参考我的另一篇文章,

快速掌握es6+新特性及es6核心语法盘点;

对let和const以及es6的新特性有详细的介绍。

3.更近一步——变量提升的优先级

直接剖出问题:

var a = 1;
function a(){
    console.log(a)
}
console.log(a)

此时代码会打印什么呢?答案是会打印1。这个问题也是我之前面试一些求职者的过程中错误高发区,这里隐藏着一个概念:函数声明提升的优先级高于变量声明的提升。浏览器底层的实现过程是这样的:当js解析器在遇到函数声明时,会优先将其提升到定义体顶部,其次再是var声明的变量,这样就导致函数a被变量a给覆盖的情况,所以最终将打印1。

4.函数参数作用域与作用域链

作用域就是变量和函数的可访问范围,当代码在一个环境中执行时,会创建变量对象的一个作用域链(scope chain),来保证对执行环境有权访问的变量和函数的顺序访问。作用域第一个对象始终是当前执行代码所在环境的变量对象。然后会一层层向外查找,直到发现第一个指定的变量为止。

在了解完以上概念之后,我们来看看下面这个问题:

var a = {name: 'xuxi'};
function b(a){
    a.age = 12;
    a = {num: 1};
    return a
}
var a1 = b(a);
console.log(a, a1)

上面代码打印的是什么呢?其实这个是我今天出的面试题,还是因为一个朋友之前问了我这个问题,我觉得有必要总结一下。虽然今天的候选人没有答出来,但是我相信在给他解释完之后他应该不虚此行(说过了,不好意思)。

这块主要还是函数内部作用域和引用类型的一个问题。具体过程如下:

(1)我们根据之前介绍的作用域和作用域链的概念可以知道,在函数体内,变量会就近查找,而函数参数会存在于函数体内部作用域中,所以当我们把全局变量a当作入参传递给函数时,又由于全局a是引用类型,此时只是引用了它的地址,那么我们通过a.age设置属性时,全局a也会改变。 (2)第二步是将a赋予了一个新的值,此时的a根据就近查找其实是参数a,本质上是将参数a赋予了一个新的对象,这个时候和全局变量的a没有任何关系了,此时函数最后会返回一个新的对象。

综上两步分析,我们就会明白为什么打印a时输出的是{name: 'xuxi', age: 12},打印a1会输出{num: 1}了。

总结

函数声明提升,变量作用域以及作用域链这块一直是学习javascript的基础也是重点,所以希望这篇文章可以让大家更好的掌握它。 如果想了解更多webpack,node,gulp,css3,javascript,nodeJS,canvas等前端知识和实战,欢迎在公众号《趣谈前端》加入我们一起学习讨论,共同探索前端的边界。

《前端实战总结》之变量提升,函数声明提升及变量作用域详解

更多推荐

收藏
评论区

相关推荐

《前端实战总结》之使用解释器模式实现获取元素Xpath路径的算法
前端领域里基于javascript的设计模式和算法有很多,在很多复杂应用中也扮演着很重要的角色,接下来就介绍一下javascript设计模式中的解释器模式,并用它来实现一个获取元素Xpath路径的算法。 上期回顾 《前端实战总结》之迭代器模式的N1种应用场景(https://juejin.im/post/6844904008616771591)
Cors跨域解决
一、浏览器跨域问题产生 1、跨源资源共享(CORS)中文文档: https://developer.mozilla.org/zhCN/docs/Web/HTTP/Access_control_CORS 2、什么是浏览器跨域问题 指的是浏览器不能执行其他网站的脚本。JavaScript出于安全方面的考虑,不允许跨域调用其他页面的对象,即同源策略。就好比我
你所知道的JS变量作用域
变量的作用域,指的是变量在脚本代码中的可读、可写的有效范围,也就是脚本代码中可以使用这个变量的区域。在ES6之前,变量的作用域主要分为全局作用域、局部作用域(也称函数作用域)两种;在ES6及其之后,变量的作用域主要分为全局作用域、局部作用域、块级作用域这3种。相应作用域变量分别称为全局变量、局部变量、块级变量。全局变量声明在所有函数之外;局部变量是在函数体内
一篇文章带你了解JavaScript作用域
在JavaScript中,对象和函数也是变量。在JavaScript中,作用域是你可以访问的变量、对象和函数的集合。JavaScript 有函数作用域: 这个作用域在函数内变化。一、本地JavaScript变量一个变量声明在JavaScript函数内部,成为函数的局部变量。局部变量有局部作用域: 它们只能在函数中访问。JS://code here can n
ES6 常用语法
### 什么是ES6 ECMAScript 6 简称ES6, 在2015年6月正式发布~  ECMAScript 是JavaScript语言的国际标准。 我们本着二八原则,掌握好常用的,有用的~能让我们更快的上手~~~ ### 1  声明变量const  let  var ES6以前 var关键字来声明变量,无论声明在何处都存在变量提升这个事情~~会
2018年 JavaScript 明星项目
![](https://oscimg.oschina.net/oscnet/c52a3381-8d56-4509-a191-4dd76ca37bb3.jpg)在 2016年 和 2017年 之后,欢迎来到第三届 JavaScript 明星项目! 是时候回顾 2018 年 Javascript 领域的发展与变化了。 通过对比各项目过去 12 个月在 Git
2018年 JavaScript 明星项目
![](https://oscimg.oschina.net/oscnet/c52a3381-8d56-4509-a191-4dd76ca37bb3.jpg)在 2016年 和 2017年 之后,欢迎来到第三届 JavaScript 明星项目! 是时候回顾 2018 年 Javascript 领域的发展与变化了。 通过对比各项目过去 12 个月在 Git
Highcharts使用HTML表中的数据创建交互式图表教程
[Highcharts](https://www.oschina.net/action/GoToLink?url=https%3A%2F%2Fwww.evget.com%2Fproduct%2F3328)是一款纯JavaScript编写的图表库,为你的Web网站、Web应用程序提供直观、交互式图表。当前支持折线、曲线、区域、区域曲线图、柱形图、条形图、饼图、
JS中!function(){}()的理解
这种写法,是一种`立即执行函数`的写法,即IIFE等设计模式。这种函数在函数定义的地方就直接执行了。 理解IIFE设计模式的关键是要认识到,在ES6之前,JavaScript仅具有[函数作用域](https://www.oschina.net/action/GoToLink?url=https%3A%2F%2Fen.wikipedia.org%2Fwiki
JavaScript 作用域
在学习js的过程对闭包什么的,理解不好,偶然搜到这篇文章。豁然开朗,随翻译。 Javacript 中有一系列作用域的概念。对于新的JS的开发人员无法理解这些概念,甚至一些经验丰富的开发者也未必能。这篇文章主要目的帮助理解JavaScript中的一些概念如:scope,closure, this, namespace, function scope,
JavaScript作用域
一、JavaScript中无块级作用域 =================== 在Java或C#中存在块级作用域,即:大括号也是一个作用域。 ![](https://oscimg.oschina.net/oscnet/ea3e9460a4d20056c59315db47e2a0cbc2b.jpg)![](https://oscimg.oschina.ne
JavaScript图表库Highcharts发布最新版v8.2.2,修复了旧版Windows安装中的boost模块错误
[**Highcharts**](https://www.oschina.net/action/GoToLink?url=https%3A%2F%2Fwww.evget.com%2Fproduct%2F3328)是一款纯JavaScript编写的图表库,为你的Web网站、Web应用程序提供直观、交互式图表。当前支持折线、曲线、区域、区域曲线图、柱形图、条形图
JavaScript图表库Highcharts发布最新版本9.0
[**Highcharts**](https://www.oschina.net/action/GoToLink?url=https%3A%2F%2Fwww.evget.com%2Fproduct%2F3328)是一款纯JavaScript编写的图表库,为你的Web网站、Web应用程序提供直观、交互式图表。当前支持折线、曲线、区域、区域曲线图、柱形图、条形图
JavaScript易错知识点整理
前言 本文是我学习JavaScript过程中收集与整理的一些易错知识点,将分别从变量作用域,类型比较,this指向,函数参数,闭包问题及对象拷贝与赋值这6个方面进行由浅入深的介绍和讲解,其中也涉及了一些ES6的知识点。 JavaScript知识点 ------------- ### 1.变量作用域 `var a = 1; functio
Js中的跨域问题
一、什么是跨域? ======== 1.定义: ----- 跨域是指从一个域名的网页去请求另一个域名的资源。比如从www.baidu.com 页面去请求 www.google.com 的资源。但是一般情况 下不能这么做,它是由浏览器的同源策略造成的,是浏览器对JavaScript施加的安全限制。跨域的严格一点的定义是:只要 协议,域名,端口 有任何一