之前的面试中遇到过一道面试题

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(){};
  1. 给右侧的匿名函数增加函数名
  2. 以右侧函数名来执行函数
  3. 能成功吗?
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)中

  • 语言内置,所有的作用域中都有thisarguments关键字
  • 形式参数,函数的参数在整个作用域中都是有效的
  • 函数声明
  • 变量声明

上面列出的四种顺序也正是由高到底的优先级的顺序(关于这点我有所保留,我测试的结果是参数和函数的优先级都会比语言内置的优先级高,你可以把形式参数取名为arguments,或者定义一个函数名为arguments,结果内置的argument说被覆盖了),一旦一个变量名已经声明了,那么它就不可能被其他更低优先级的变量声明形式所覆盖。

谈javascript变量声明的更多相关文章

  1. 浅谈JavaScript变量声明提升

    前段时间阿里实习生内推,一面就被刷了,也是郁闷.今天系统给发通知,大致意思就是内推环节不足以了解彼此,还可以参加笔试,于是赶紧再投一次.官网流程显示笔试时间3月31日,时间快到了,开始刷题.网上搜了一 ...

  2. javascript变量声明 及作用域

    javascript变量声明提升(hoisting) http://openwares.net/js/javascript_declaration_hoisting.html 可能要FQ一下 java ...

  3. 【转】javascript变量声明 及作用域

    javascript变量声明提升(hoisting) javascript的变量声明具有hoisting机制,JavaScript引擎在执行的时候,会把所有变量的声明都提升到当前作用域的最前面. 先看 ...

  4. javascript变量声明及作用域总结

    javascript变量声明及作用域总结 一.总结 一句话总结:还是得好好看书,光看视频是不得行的,浅学无用,要相互印证,要真正理解才有用,比如<Javascript权威指南> 书 1.j ...

  5. JavaScript 变量声明提升

    JavaScript 变量声明提升 一.变量提升的部分只是变量的声明,赋值语句和可执行的代码逻辑还保持在原地不动 二.在基本的语句(或者说代码块)中(比如:if语句.for语句.while语句.swi ...

  6. JavaScript变量声明与变量声明提前

    JavaScript变量声明 JavaScript中存储数据的容器称为变量.用关键字和标识符创建新变量的语句,称为变量声明.可以通过关键字var进行变量声明,在ES6中增加了let.const关键字声 ...

  7. JavaScript变量声明提前

    上周四吃完午饭,leader发了一道JavaScript的题目给我们做,我们Team里面有做前端的,有做后台的,也有做mobile web的,所以大家对题目的理解各自都不一样,然后在QQ讨论组里面进行 ...

  8. JavaScript 变量声明提前

    <JavaScript权威指南>中指出:JavaScript变量在声明之前已经可用,JavaScript的这个特性被非正式的称为声明提前(hoisting),即JavaScript函数中声 ...

  9. JavaScript 变量声明:var、let、const

    1. 概述 1.1 说明 在ES5 声明变量的方法:var命令和function命令. 在ES6 声明变量的方法:var命令.function命令.let命令.const命令.import命令.cla ...

随机推荐

  1. ExtJs6获取form里的数据

    1.PanoramForm.js form的items部分 items: [{ xtype: 'form', id:'customerF', modelValidation: true, defaul ...

  2. JSP慕课网之Session

    会话保存在服务器的内存里. sessionId可以通过进入http://localhost:8888/进入Tomcat的Manager App进行查看,点击项目的sessions可以看到session ...

  3. GCC和G++区别

    原文:http://www.cnblogs.com/samewang/p/4774180.html 看的Linux公社的一篇文章,觉得不错,内容复制过来了. 其实在这之前,我一直以为gcc和g++是一 ...

  4. 如何在环境变量里配置tomcat

    安装好后,配置环境变量:计算机--右击--属性--高级系统设置设置--环境变量 4 新建系统变量 变量名:JAVA_HOME 变量值:C:\Program Files\Java\jdk1.7.0(这个 ...

  5. C# 匿名对象(匿名类型)、var、动态类型 dynamic

    本文是要写的下篇<C#反射及优化用法>的前奏,不能算是下一篇文章的基础的基础吧,有兴趣的朋友可以关注一下. 随着C#的发展,该语音内容不断丰富,开发变得更加方便快捷,C# 的锋利尽显无疑. ...

  6. Selenium 定位网页元素

    第一 定位元素辅助工具 IE中在元素上右击 ->  “检查元素”,或按F12键打开开发者工具: Chrome中在元素上右击 -> “审查元素”,或按F12键打开开发者工具: Firefox ...

  7. 创建WIFI热点--附近的百度帐号

    前提准备: 前提是当前的网卡必须支持AP(Acess Point)模式, 也可以使用外接的usb网卡 nodeJS环境 安装create_AP 使用create_AP创建热点, 安装方式为: git ...

  8. 转:【Java并发编程】之八:多线程环境中安全使用集合API(含代码)

    转载请注明出处:http://blog.csdn.net/ns_code/article/details/17200509     在集合API中,最初设计的Vector和Hashtable是多线程安 ...

  9. yyt

    红颜迤逦隔云梯, 相思萦系解花语. 我有相思千般意, 百磨不灭铭肝肠.

  10. 团队作业8——Beta 阶段冲刺1st day

    一.今日站立式会议照片 二.每个人的工作 (1) 昨天已完成的工作: 今天是冲刺的第一天,昨天完成的是团队成员任务的分配 (2) 今天计划完成的工作: 界面的完善 (3) 工作中遇到的困难: 对于界面 ...