变量提升

JavaScript的变量提升有两种,用var声明的变量以及用function声明的变量。

用var声明的变量

我们先来看下面这段代码,a的值是多少

代码1


console.log(a); var a;

按照以往编程语言的思路来看,代码自上而下运行,按这种思路,会报错,因为执行到第2行时,变量a还没有定义,所以会报错a is not defined

然而事实上答案是undefined

好,抱着疑惑,我们看下面的代码

var a;
console.log(a);

我们发现,这两段代码是一样的,那么又有一个新的问题,是不是有没有var a都无所谓,它的答案始终是undefined,才造成了以为变量会提升的错觉,于是我写了代码3

代码3

console.log(a);

好,它终于报错了,所以这证明了javaScript代码并不是自上而下执行的,至少从表面看上面是这样的。

于是我们再看代码4

代码4

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

因为变量提升嘛,所以答案是2,然而事实上,它依然是undefined,why?

这时候我们有请编译器这位负责语法分析及代码生成等脏活累活的大佬。

编译器在看到var a = 2;,它会将其看做两个声明,var a;a = 2,第一个声明在编译阶段进行,第二个声明会被原地等待执行阶段。

也就是说上面代码,会变成下面的这段代码

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

所以最终会是undefined

好,我在啰嗦一下,看这段代码5

代码5

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

我想大家应该已经知道这段代码执行时的真正顺序及其答案了,没错,答案是2,但我想说的是把第2行给注释掉,答案依然是2,但这个和变量提升没啥关系了,是严格模式与非严格模式的锅,在非严格模式下允许开发者可以不使用声明变量的关键字,但在严格模式下是不可以的,它会报错的。

用function声明的变量

var一样,function声明的变量依然会提升。

log(5);

function log(mes){
console.log(mes)
}

按照之前的变量提升的理解,这段代码的真正顺序是这样的,

function log(mes){
console.log(mes)
} log(5);

很好,很正确,那么再看下一段代码

log(5);

var log = function(mes){
console.log(mes)
}

它报错了,log is not a function,从这里我们可以看出,这种函数表达式是不会被提升的,只有函数声明才会被提升,试着在最前面新增一行代码console.log(log),会先输出undefined

所以这里的真正顺序是

var log;
log(); //这时候只是声明了log这个变量,并不是函数,却用函数的方法调用它,所以会报错,说这不是一个函数。
log = function(mes){
console.log(mes)
}

在function里用var声明变量

我们虽然知道,var声明的变量会提升,但并不知道会提升到哪个程度。

在此之前来看一段代码

var a = 4;

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

答案是5,4,先输出5,再输出4。

var声明的变量是有函数作用域的,所以foo里的a和foo外面的a没有任何关系,这种情况正是我想要的。

再改下代码


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

答案是5,a is not defined

第4行代码输出5,第9行报错。

这种情况就是变量提升只会提升到变量所在的 作用域的顶部,不会提升到父级作用域。

因此可以得出一个结论:变量提升只会将变量提升到自己所在的作用域的顶部

函数优先

既然用varfunction的变量都有提升的功能,那如果同一个变量用这两种都声明会怎样,好吧,看标题就知道了,函数优先。

具体看下代码

foo();

var foo;

function foo(){
console.log(1)
} foo = function(){
console.log(2)
}

答案是1

这段代码其实这样子的

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

仔细一看,var foo;没了,没错,它被引擎忽略了,认为重复声明所以把它抛弃了。

好,既然var声明的变量比不了函数声明,那就用函数声明,多次声明同个变量。


foo()
function foo(){
console.log(1);
}
foo()
function foo(){
console.log(2);
}
foo()
function foo(){
console.log(3);
} foo()

foo声明了三次,调用了四次,每次调用的结果都是3,所以最后的函数声明会覆盖之前的函数声明

但是var还想挣扎一下,觉得还是有必要证明自己的存在感的。


foo()
function foo(){
console.log(1);
}
var foo;
foo()
foo = function(){
console.log(2);
}
foo()
function foo(){
console.log(3);
} foo()

仔细看,中间那部分代码改了,依次输出3,3,2,2

虽然var foo被忽略了,但下面的函数还是有用的,这段代码可以看成是这样的

function foo(){
console.log(3);
} foo();//3
foo();//3
foo = function(){
console.log(2);
}
foo();//2
foo();//2

在普通块内部声明函数

之前是在作用域声明函数,现在来块里面声明函数

function foo(){

	console.log(b); // undefined
b(); //TypeError: b is not a function var a = true; if(a){
function b(){
console.log(2)
}
//下面这段代码和上面的结果一样
// var b = function(){
// console.log(2)
// }
}
//b() --> 这里会被执行 } foo()

从上面看上去,b是undefined,证明这个变量还是有的,只不过它并不是一个函数,这情况和用函数表达式差不多。

总结

  • 提升分为函数声明提升和变量声明提升
  • 声明变量用var,声明函数用function
  • 变量提升会将变量提升到自己所在作用域的顶部
  • 函数表达式不存在提升的机制。
  • 函数声明和变量声明同时声明同一个标识符时,函数声明优先
  • 多个函数声明同一个标识符时,最后一个声明覆盖先前的声明

JavaScript的变量提升机制的更多相关文章

  1. javascript中变量提升的理解

    网上找了两个经典的例子 var foo = 1; function bar() { if (!foo) { var foo = 10; } alert(foo); } bar(); // 10 var ...

  2. JavaScript:变量提升和函数提升

    第一篇文章中提到了变量的提升,所以今天就来介绍一下变量提升和函数提升.这个知识点可谓是老生常谈了,不过其中有些细节方面博主很想借此机会,好好总结一下. 今天主要介绍以下几点: 1. 变量提升 2. 函 ...

  3. 漫谈JavaScript中的提升机制(Hoisting)

    前言 刚接触到JavaScript的时候,便知道JavaScript是按顺序执行的,是如浏览器的解析DOM树一样的流程,解析DOM结构的时候,如果遇到JS脚本或者外联脚本便会停止解析,继续下载脚本之后 ...

  4. JavaScript中变量提升是语言设计缺陷

    首先纠正下,文章标题里的 “变量提升” 名词是随大流叫法,“变量提升” 改为 “标识符提升” 更准确.因为变量一般指使用 var 声明的标识符,JS 里使用 function 声明的标识符也存在提升( ...

  5. JavaScript的变量提升

    在JavaScript中,var变量具有函数级作用域,而且是整个函数作用域.为什么会是整个函数作用域呢?因为var变量具有变量(声明)提升功能,能将变量声明隐式的提升到函数体的顶部.这样做的一个好处就 ...

  6. Javascript 的变量提升与预解析

    一.什么是变量提升 在ES6之前,JavaScript没有块级作用域(一对花括号{}即为一个块级作用域),只有全局作用域和函数作用域.变量提升即将变量声明提升到它所在作用域的最开始的部分 二.怎么实现 ...

  7. javascript Hoisting变量提升

    1. 看人家举的两个例子,我认为这里的判断是否定义: !var 其实就是 指是否在函数function里面定义了.只有在funciton里面定义了了,js才hoist到最上面去找这个变量的值,否则就按 ...

  8. JavaScript中变量提升------Hoisting

    原谅链接:http://www.cnblogs.com/damonlan/archive/2012/07/01/2553425.html 因为这个问题很是经典,而且容易出错,所以在介绍一次.哈哈.莫怪 ...

  9. JavaScript之变量提升

    变量提升:在JavaScript中,页面加载时,会将用var声明的变量提升到作用域的最前端,只能提升声明,不能提升赋值 如果变量先赋值再使用,可以省略关键字var 如果先使用变量,再赋值,不可以省略关 ...

随机推荐

  1. 2.7 Axure rp (快速原型设计工具)

    一.   Axure rp 下载安装 直接百度栏输入Axure rp即可下载.安装无特别处,一直点击下一步即可. 安装的如果是英文版,可以下载汉化包,进行汉化. 汉化参照网址:http://www.a ...

  2. DVWA全级别之XSS(Reflected)、XSS(Stored)【跨站脚本攻击】

    XSS XSS,全称Cross Site Scripting,即跨站脚本攻击,某种意义上也是一种注入攻击,是指攻击者在页面中注入恶意的脚本代码,当受害者访问该页面时,恶意代码会在其浏览器上执行,需要强 ...

  3. 2.springboot------微服务

    什么是微服务? 微服务是一种架构风格,它要求我们在开发一个应用的时候,这个应用必须构建成一系列小服务的组合:可以通过http的方式进行互通.要说微服务架构,先得说说过去我们的单体应用架构. 单体应用架 ...

  4. selenium-JavaScript的处理

    JavaScript的处理 在自动化过程中,遇到js处理的元素,需要使用js语言对元素进行操作,例如,滑动到浏览器的底部或者顶部,时间控件的处理,元素可见不可见以及富文本的处理等,都需要js语言的支持 ...

  5. C++算法导论第九章O(n)期望选择序列第i小的数字

    #include<iostream> #include<vector> #include<algorithm> #include<time.h> usi ...

  6. ASP.NET Core 使用过滤器移除重复代码

    USING ACTIONFILTERS TO REMOVE DUPLICATED CODE ASP.NET Core 的过滤器可以让我们在请求管道的特定状态之前或之后运行一些代码.因此如果我们的 ac ...

  7. android:Android 6.0权限控制代码封装

    新建的Activity类可以继承这个Activity,这个类封装了关于新版的权限处理相关的代码 使用方法: package com.glsite.phone; import android.conte ...

  8. SQL过滤条件on和where

    在使用left jion时,会生成一张中间的临时表,然后再将这张临时表返回给用户. on和where条件的区别如下:1. on条件是在生成临时表时使用的条件,它不管on中的条件是否为真,都会返回左边表 ...

  9. caffe_ocr开源项目学习笔记

    本机配置cuda8.0使用的cudnn是下面要说的重点,vs2015,win10,1080Ti 下载了开源项目:https://github.com/senlinuc/caffe_ocr 编译的时候报 ...

  10. 【游戏体验】Shoot'm(暴打火柴人)

    >>>点此处可试玩无敌版<<< 注意,本游戏含有少量暴力元素,13岁以下的儿童切勿尝试本款游戏 生活有压力,学习不如意,你可以尝试这款游戏发泄心中的不满 个人测评 ...