变量声明提升 Vs. 函数声明提升
1. 变量声明提升
先看以下代码:
1)var in_window = "a" in window; console.log(in_window);
2)var in_window = "a" in window; console.log(in_window); if(!("a" in window)) { var a = 1; }
3)var a; var in_window = "a" in window; console.log(in_window); if(!("a" in window)) { a = 1; }
控制台输出的结果分别是:false true true。如何解释? 这是由于在js的变量作用域中有个规则:所有变量声明都在范围作用域的顶部!也就是说,在2)代码中,if语句块内的申明的变量a,会自动提到上面去申明。其等价于3)。
由上述的分析可知,可以理解下面代码的输出结果是undefined。
if(!("a" in window)) { var a = 1; } console.log(a); //undefined 该代码其实相当于:var a; if(!("a" in window")) { a = 1; } console.log(a);
再试一次:
var s = ''; if (false) { var a = 1; }
浏览器中的调试结果如下:
有图有真相。变量a的声明的确提升了。
巩固题:
var s = ''; while(false) { var a = 1; } console.log(a); //undefined
if(!("a" in window)) { a = 1 } console.log(a); //1
console.log(a); //报错,"ReferenceError: a is not defined."
2. 函数声明提升
定义函数有两种方式:一种是函数申明,另一种是函数表达式。函数申明形式:function functionName(arg0, arg1, arg2) { //函数体 },函数表达式形式:var functionName = function(arg0, arg1, arg2) { //函数体 } 。关于函数申明,它有一个重要特征就是函数声明提升,看下面的例子。
sayHi(); function sayHi() { console.log("hi"); }
浏览器中的调试结果如下: 发现函数sayHi已经被声明了,并且其值为sayHi函数。第一行代码执行后,输出hi。
若采用函数表式的形式,此时我们能看到变量声明提升的效果。
sayHi(); var sayHi = function() { console.log("hi"); }
在浏览中的调试效果如下:发现变量sayHi提升了,它的值是undefined,第一行代码执行的话,会报错:"TypeError:undefined is not a function"。
接下来的例子就很好理解。
if(!("a" in window)) { var a = function() { window.a = 1; } } console.log(a); //undefined 该代码等价于: var a; if(!("a" in window)) { a = function() { window.a = 1; } } console.log(a); 其实无论if语句块中的a被定义成何种类型的值,a的申明都提前了。(变量提升)
将上述代码变形如下:
if(!("a" in window)) { function a() { window.a = 1; }} console.log(a); //function a() { window.a = 1;}(函数申明提升)
由此可以总结出,所有函数声明也在范围作用域的顶部。那么函数声明和变量声明,哪个的优先级高呢?
3. 变量声明 VS 函数声明
如下图对比所示:函数声明会覆盖变量声明。
VS
VS
但是如果在变量声明的同时,对变量进行初始化,情况会有所不同。对同一个变量名,声明变量同时初始化变量优先级高于函数声明。
VS
VS
再练几题:
function a() { return false; } var s = ''; if(a()) { var a = 1; } console.log(a);
上述代码输出的a值为:function a() { return false; }
function a() { return true; } var s = ''; if(a()) { var a = 1; } console.log(a);
上述代码输出的a值为:1
function a() { return true; } var a; var s = ''; if(a()) { a = 1; } console.log(a);
上述代码输出的a值为:1
由对上述代码的分析:可以总结出如下规律:
1)变量声明提升:变量申明在进入执行上下文就完成了。
只要变量在代码中进行了声明,无论它在哪个位置上进行声明, js引擎都会将它的声明放在范围作用域的顶部;
2)函数声明提升:执行代码之前会先读取函数声明,意味着可以把函数申明放在调用它的语句后面。
只要函数在代码中进行了声明,无论它在哪个位置上进行声明, js引擎都会将它的声明放在范围作用域的顶部;
3)变量or函数声明:函数声明会覆盖变量声明,但不会覆盖变量赋值。
同一个名称标识a,即有变量声明var a,又有函数声明function a() {},不管二者声明的顺序,函数声明会覆盖变量声明,也就是说,此时a的值是声明的函数function a() {}。注意:如果在变量声明的同时初始化a,或是之后对a进行赋值,此时a的值变量的值。eg: var a; var c = 1; a = 1; function a() { return true; } console.log(a); //1
时间:2014-10-17
地点:合肥
参考:http://www.cnblogs.com/yexiaochai/archive/2013/04/22/3034949.html
变量声明提升 Vs. 函数声明提升的更多相关文章
- 原型模式故事链(4)--JS执行上下文、变量提升、函数声明
上一章:JS的数据类型 传送门:https://segmentfault.com/a/11... 好!话不多少,我们就开始吧.对变量提升和函数声明的理解,能让你更清楚容易的理解,为什么你的程序报错了~ ...
- JS 函数提升&变量提升以及函数声明&函数表达式的区别
感谢原文作者:迟早会有猫 原文链接:https://www.cnblogs.com/SidselLoong/p/10515809.html 今天看js的变量提升问题,里面提到了函数提升.然后发现自己之 ...
- 【JS】函数提升变量提升以及函数声明和函数表达式的区别
今天看js的变量提升问题,里面提到了函数提升.然后发现自己之前一直把函数声明和函数表达式弄错,导致函数提升出错 一.变量提升 console.log(a) var a=100 //undefined ...
- 【JS点滴】声明提前,变量声明提前,函数声明提前,声明提前的先后顺序
声明提前,函数声明提前,好吧,老生常谈的问题了.正好,前些天在掘金看到一道关于声明提前的笔试题,那么这里就以这道题来作为本文的引子吧,代码如下: console.log(a)//? a();//? ; ...
- js变量的作用域、变量的提升、函数的提升
变量的作用域在函数之外声明的变量,叫做全局变量,因为它可被当前文档中的任何其他代码所访问.在函数内部声明的变量,叫做局部变量,因为它只能在当前函数的内部访问. ECMAScript 6 之前的 Jav ...
- Js 变量声明提升和函数声明提升
Js代码分为两个阶段:编译阶段和执行阶段 Js代码的编译阶段会找到所有的声明,并用合适的作用域将它们关联起来,这是词法作用域的核心内容 包括变量声明(var a)和函数声明(function a(){ ...
- js中变量提升(一个是变量,一个是函数表达式都会存在变量提升,函数声明不存在)
一.变量提升 在ES6之前,JavaScript没有块级作用域(一对花括号{}即为一个块级作用域),只有全局作用域和函数作用域.变量提升即将变量声明提升到它所在作用域的最开始的部分.上个简历的例子如: ...
- javascript变量声明提升和函数声明提升
在ES6之前,JavaScript没有块级作用域(一对花括号{}即为一个块级作用域),只有全局作用域和函数作用域.变量提升即将变量声明提升到它所在作用域的最开始的部分. JS的解析过程分为两个阶段:预 ...
- JavaScript变量提升和函数声明预解析
1.首先理解函数作用域 在JavaScript中,变量的定义并不是以代码块作为作用域的,而是以函数作用作用域的.也就是说,如果变量是在某个函数中定义的,那么它在函数以外的地方是不可见的.而如果该变量是 ...
随机推荐
- C语言回顾-函数和位运算
1.函数的概述 功能独立的代码块 C语言由若干函数组成 1)从定义分,库函数和用户定义函数两种 2)从返回值分,有返回值函数和无返回值函数 3)从参数分,无参函数和有参函数 2.形参和实参 1)形参定 ...
- nodejs框架express准备登录
目录: 安装模板 静态资源 添加视图 渲染视图 url重定向 模板引擎 从本节课程开始我们要使用express框架实现一个简单的用户登陆功能,让我们先准备一下相关资源. 在nodejs中使用expre ...
- Java Spring DI之旅
做过.NET的人很多都用过Microsoft Enterprise Library,里面有一个Dependency injection工具Unity,我们可以使用它来实现依赖注入:什么是依赖注入呢?我 ...
- EasyUI中在表单提交之前进行验证
使用EasyUi我们可以在客户端表单提交之前进行验证,过程如下:只需在onSubmit的时候使用return $("#form1").form('validate')方法即可,E ...
- 简单练习题2编写Java应用程序。首先定义一个描述银行账户的Account类,包括成员变 量“账号”和“存款余额”,成员方法有“存款”、“取款”和“余额查询”。其次, 编写一个主类,在主类中测试Account类的功能
编写Java应用程序.首先定义一个描述银行账户的Account类,包括成员变 量“账号”和“存款余额”,成员方法有“存款”.“取款”和“余额查询”.其次, 编写一个主类,在主类中测试Account类的 ...
- C#获取文件时间
在NTFS下,文件的创建及修改时间可以精确到毫秒,以下是测试过程. DirectoryInfo diSource = new DirectoryInfo(@"C:\Users\不告诉你\De ...
- 【Spring】Junit加载Spring容器作单元测试
如果我们需要对我们的Service方法作单元测试,恰好又是用Spring作为IOC容器的,我们可以这么配置Junit加载Spring容器,方便做单元测试. > 基本的搭建 (1)引入所需的包 & ...
- CentOS 7 安装、配置、使用 PostgreSQL 9.5及PostGIS2.2
学习CentOS下安装使用PostgreSQL [安装过程] 1.添加RPM yum install https://download.postgresql.org/pub/repos/yum/ ...
- Windows server 2012 AD DS 搭建步骤
服务器版本:Windows server 2012 1. 配置网络,由于本机会搭建DNS服务器,因此首选DNS服务器设置为127.0.0.1 2. 打开服务器管理器 3. 点击添加角色和功能,下 ...
- Sprint(第四天11.17)
燃尽图