谈javascript变量声明
之前的面试中遇到过一道面试题
var a =10;
(function(){
console.log(a);
var a =20;}
)()
- 短短5行代码log的结果是什么?
- 如果把
var a = 20;和console.log(a)语句顺序对调呢?
这道题目的答案是undefined。不是10。
关键在于javascript的变量声明有一个hoisting机制,变量声明永远都会被提升至作用域的最顶端(注意测试还只是声明,还没有赋值)。其实上面的语句相当于:

var a =10;
(function(){
var a;//在这里对变量hoisting,先声明
console.log(a);
a =20;//再赋值
})()

再精简一点:

bla =2
var bla; // 这是分割线,上下代码的效果其实是一样的 var bla;
bla =2;

也就是先使用,再声明(注意是声明,还没有赋值),这样一来,声明和赋值就被分开来了。所以最佳实践都推荐最好在函数的顶端把需要使用的变量首先声明一遍。
同理,我们可以理解下面的代码也是会报错的
f()//明显这里有错,因为f还没有被赋一个函数
var f =function(){
console.log("Hello");
}
但有一个问题,如果将上例f的函数声明修改一下,还会报错吗
f()//可以运行吗?
function f(){
console.log("Hello");
}
这里我其实想强调的是两种函数声明的var f = function () {}和function f() {}差别。
事实上,javascript中所有的函数声明(function declarations)和变量声明(variable declarations)都会被提升(hoisted)至它们所在作用域的最顶端。需要注意的是函数声明只有一种,也就是function f() {}的形式。而var f = function () {}是什么?你可以理解为它是将一个匿名函数(当然也可以取函数名,下面会解释)赋值给了一个变量。
就哪上面两个例子来说,同样是想实现先使用再定义的效果。只有第二种有用,虽然函数f在使用之后才定义,但是在javascript解释器中,它仍然是先于执行语句被定义的。
而第一个例子,执行的效果是这样的
var f;
f()//没有定义任何函数,当然无法执行
f =function(){
console.log("Hello");
}
这么看来,虽然javascript是允许先执行再声明,但切勿这么做,请遵循先声明再使用的好习惯。
再看看另一种情况,如果我把之前的函数定义
var f =function(){};
- 给右侧的匿名函数增加函数名
- 以右侧函数名来执行函数
- 能成功吗?
var f =function ab(){};
ab();
答案是否定的,因为上面的代码对f函数的定义是以命名函数表达式(Named Function Expressions),而并非真正的函数声明,注意该函数名只在该函数的作用域内有用。下面这段代码充分说明了它的意义:

var f =function foo(){
return typeof foo;
};
typeof foo;// "undefined"
f();// "function"

那么如此声明还有什么意义呢?好吧,就我目前找到的资料而言,这样做的好处就是便于调试。
接下来考虑一些意想不到的边缘,虽然我觉得一个程序员写出下面的代码有点自找苦吃,而且应该是在实战中避免的,但作为考试的题目来说是值得一说的。比如对比下面两段代码:

function value(){
return 1;
}
var value;
alert(typeof value);//"function"
function value(){
return 1;
}
var value =1;
alert(typeof value);//"number"

第一段代码想说明的是函数声明会覆盖变量声明,注意是声明,还没有赋值。如代码中,虽然同名变量在函数后再次声明,但是typeof的结果仍然是function
第二段代码想说明的是函数声明不会覆盖变量赋值或者说初始化,如代码所示
Name Resolution Order
为什么会有上面的结果,为什么函数的声明会覆盖变量的声明。就是因为name resolution order。我不知道怎么翻译这个名词,暂且就翻译为名称解析顺序吧。
在javascript中,一个变量名(name)有四种方式进入作用域(scope)中
- 语言内置,所有的作用域中都有
this和arguments关键字 - 形式参数,函数的参数在整个作用域中都是有效的
- 函数声明
- 变量声明
上面列出的四种顺序也正是由高到底的优先级的顺序(关于这点我有所保留,我测试的结果是参数和函数的优先级都会比语言内置的优先级高,你可以把形式参数取名为arguments,或者定义一个函数名为arguments,结果内置的argument说被覆盖了),一旦一个变量名已经声明了,那么它就不可能被其他更低优先级的变量声明形式所覆盖。
谈javascript变量声明的更多相关文章
- 浅谈JavaScript变量声明提升
前段时间阿里实习生内推,一面就被刷了,也是郁闷.今天系统给发通知,大致意思就是内推环节不足以了解彼此,还可以参加笔试,于是赶紧再投一次.官网流程显示笔试时间3月31日,时间快到了,开始刷题.网上搜了一 ...
- javascript变量声明 及作用域
javascript变量声明提升(hoisting) http://openwares.net/js/javascript_declaration_hoisting.html 可能要FQ一下 java ...
- 【转】javascript变量声明 及作用域
javascript变量声明提升(hoisting) javascript的变量声明具有hoisting机制,JavaScript引擎在执行的时候,会把所有变量的声明都提升到当前作用域的最前面. 先看 ...
- javascript变量声明及作用域总结
javascript变量声明及作用域总结 一.总结 一句话总结:还是得好好看书,光看视频是不得行的,浅学无用,要相互印证,要真正理解才有用,比如<Javascript权威指南> 书 1.j ...
- JavaScript 变量声明提升
JavaScript 变量声明提升 一.变量提升的部分只是变量的声明,赋值语句和可执行的代码逻辑还保持在原地不动 二.在基本的语句(或者说代码块)中(比如:if语句.for语句.while语句.swi ...
- JavaScript变量声明与变量声明提前
JavaScript变量声明 JavaScript中存储数据的容器称为变量.用关键字和标识符创建新变量的语句,称为变量声明.可以通过关键字var进行变量声明,在ES6中增加了let.const关键字声 ...
- JavaScript变量声明提前
上周四吃完午饭,leader发了一道JavaScript的题目给我们做,我们Team里面有做前端的,有做后台的,也有做mobile web的,所以大家对题目的理解各自都不一样,然后在QQ讨论组里面进行 ...
- JavaScript 变量声明提前
<JavaScript权威指南>中指出:JavaScript变量在声明之前已经可用,JavaScript的这个特性被非正式的称为声明提前(hoisting),即JavaScript函数中声 ...
- JavaScript 变量声明:var、let、const
1. 概述 1.1 说明 在ES5 声明变量的方法:var命令和function命令. 在ES6 声明变量的方法:var命令.function命令.let命令.const命令.import命令.cla ...
随机推荐
- 用EditPlus编辑器配置C#开发环境
用EditPlus配置配置C#开发环境... -------------------- ---------------------------- 配置步骤: 1.打开EditPlus,找到 工具 —& ...
- C# 隐藏文件
void SerializeXmlNodes(XmlSerializer serialize, string filePath, List<XmlNode> nodes) { using ...
- 如何在环境变量里配置tomcat
安装好后,配置环境变量:计算机--右击--属性--高级系统设置设置--环境变量 4 新建系统变量 变量名:JAVA_HOME 变量值:C:\Program Files\Java\jdk1.7.0(这个 ...
- Mybatis --- 创建方法、全局配置
总体介绍:MyBatis实际上是Ibatis3.0版本以后的持久化层框架[也就是和数据库打交道的框架]! 和数据库打交道的技术有: 原生的JDBC技术--->Spring的Jd ...
- python条件判断与循环
条件判断 1.python缩进规则: 如果if语句判断是True,就把缩进的语句执行了,否则,什么也不做,比如: age=20 if age >= 18: print('your age is' ...
- JSON取值(key是中文或者数字)方式详解
JSON取值(key是中文或者数字)方式详解 先准备一个json对象用于演示 var json = {'name':'zhangsan', '年龄':23, 404:'你可能迷路了'}; 使用JS中w ...
- Docker 集群环境实现的新方式
近几年来,Docker 作为一个开源的应用容器引擎,深受广大开发者的欢迎.随着 Docker 生态圈的不断建设,应用领域越来越广.云计算,大数据,移动技术的快速发展,加之企业业务需求的不断变化,紧随技 ...
- Springmvc_validation 效验器
springmvc-validation效验器的使用介绍 对于任何一个应用来说,都会做数据的有效性效验,但是只在前端做并不是很安全,考虑到安全性這个时候会要求我们在服务端也对数据进行有效验证,spri ...
- 32位汇编第二讲,编写窗口程序,加载资源,响应消息,以及调用C库函数
32位汇编第二讲,编写窗口程序,加载资源,响应消息,以及调用C库函数 (如果想看所有代码,请下载课堂资料,里面有所有代码,这里会讲解怎么生成一个窗口程序) 一丶32位汇编编写Windows窗口程序 首 ...
- 【C# in depth 第三版】温故而知新(1)
声明 本文欢迎转载,原文地址:http://www.cnblogs.com/DjlNet/p/7192354.html 前言 关于这本书(<深入理解C# 第三版>)的详细情况以及好坏,自行 ...