写在前面的话:每个人都会犯错——有时候‘孰能无过,过而能改,善莫大焉’,有时候知道自己错了却没有机会更改。其实,错了并不仅仅是错了,做错了,除了及时改正和弥补之外,最重要的是为自己犯的错承担所有责任。

2009年3月14日,我去参加网易互动的专场招聘会,应聘网页工程师的职位。有幸参加笔试,然后有幸栽在笔试,呵呵。废话少说,抓出音响极深的一题重新研究研究。

题目大概是:写出如下代码的输出结果并进行分析

var tt = 'aa';
function test(){
    alert(tt);
    var tt = 'dd';
    alert(tt);
}
test();

“太简单了!”这是我当时看到这个题目是的第一想法,于是轻率答题竟成我的致命之伤。我的答案是——aa和dd,解析:第一次输出全局变量的结果,然后局部变量tt覆盖全局变量所引用的值,所以第二次输出结果是dd。

任何人见我如此作答,都会认为我是在扫盲——想法及其幼稚(我也这么认为)!

网易啊,怎么可能会满意于这种答案!

正确的答案应该是:undefined和dd

为什么第一次alert的结果是undefined呢?要解释得清楚明白需要用到Javascript的词法作用域。

Javascript中的函数“在定义它们的作用域里运行,而不是在执行它们的作用域里运行”,这是权威指南里抽象而精辟的总结。

Javascript的逻辑默认在一个全局作用域中执行,如以上程序段中的“var tt='aa';”就是定义一个全局作用域的全局变量(如果以上代码段不是摘自某个函数链的话)。而test()函数内部的逻辑必须在原有的作用域(全局作用域)链再添加test函数本身的作用域(局部性)——这些思想几乎在每一种语言中都是如此定义的,然而Javascript作用域链的特别之处在于函数内部能够嵌套函数的定义(这是闭包的基础。注:在JS中函数是唯一形式的代码作用域)

嵌套的内部函数可以调用外部函数(被嵌套的函数)的变量和其他嵌套函数(函数是一种数据)。如果是在外部函数内调用嵌套函数,那么调用对象不变,当外部函数执行完毕后所有数据(包括外部函数和嵌套的内部函数)都将被垃圾回收机制收集——这一点还不能体现出‘闭包’的精华。有一种情况,就是Javascript允许外部调用嵌套的内部函数,即使被嵌套函数已经被‘垃圾收集’——最常见的就是在‘某个函数’中用其嵌套的内部函数定义某些元素的响应事件,页面载入的时候被嵌套函数(‘某个函数’)已经执行完毕(被垃圾回收),但当事件触发的时候仍然会有响应的动作,而且响应函数中还可能调用到在被嵌套函数(‘某个函数’)中定义的变量最终值(不是被垃圾回收了吗?)。

关于闭包的知识和示例有很多资料可供查询,我不想叙述。

本文的重点是以下非常重要的细节:

调用对象位于作用域链的前端,局部变量(在函数内部用var声明的变量)、函数参数及Arguments对象都在函数内的作用域中——这意味着它们隐藏了作用域链更上层的任何同名的属性

即,在以上程序片段中,test函数内部的“var tt='dd'”将会致使“var tt='aa'”在test函数被调用时完全被隐藏。而且,tt是在第一个alert语句之后定义,所以在调用到第一个alert时,tt是还没有被赋值的。这样说可能会清楚一点,即,在定义test函数时,当定义第一个alert(tt)时,这里会记录tt是作用域链中的一个变量但不会记录它(tt)的值,函数定义完毕后tt就添加到作用域里,所以第一个alert语句能够找到该作用域里的tt(即,相当于找到一个已经在函数内部声明,但未被赋值的tt)。

以上程序片段的执行结果与以下片段的结果相同:

var tt = 'aa';
function test(){
    var tt;
    alert(tt);
    tt = 'dd';
    alert(tt);
}
test();

Javascript的作用域不可简单的用C++等语言的思维来理解啊!C++在调用函数之前必须先声明或定义,而Javascript没必要。在Javascript中可以先调用函数,后再定义(不用在调用之前作任何声明)。因为在调用函数时,Javascript是向作用域链要函数的定义(函数在定义它们的作用域里运行,而不是在执行它们的作用域里运行

如以上代码写成:

var tt = 'aa';
test();  //先调用后再定义
function test(){
    alert(tt);    //undefined
    var tt = 'dd';
    alert(tt);    //dd
}

以上代码片段虽然能够得到相同的结果,但最好不要那样写啦,习惯不好,代码不好维护。

重申一下本文的重点:

函数在定义它们的作用域里运行,而不是在执行它们的作用域里运行

调用对象位于作用域链的前端,局部变量(在函数内部用var声明的变量)、函数参数及Arguments对象都在函数内的作用域中——这意味着它们隐藏了作用域链更上层的任何同名的属性

转载于:https://www.cnblogs.com/wangbin/archive/2010/11/06/1870637.html

再探Javascript词法作用域相关推荐

  1. JavaScript词法作用域的简单介绍

    by Michael McMillan 迈克尔·麦克米兰(Michael McMillan) JavaScript词法作用域的简单介绍 (An easy intro to Lexical Scopin ...

  2. JavaScript词法作用域和动态作用域

    2019独角兽企业重金招聘Python工程师标准>>> 作用域 作用域是指代码中定义变量的区域. 作用域规定了如何查找变量,也就是确定当前代码执行对变量的访问权限 JavaScrip ...

  3. JavaScript夯实基础系列(一):词法作用域

      作用域是一组规则,规定了引擎如何通过标识符名称来查询一个变量.作用域模型有两种:词法作用域和动态作用域.词法作用域是在编写时就已经确定的:通过阅读包含变量定义的数行源码就能知道变量的作用域.Jav ...

  4. 如何延长作用域链_通过实例理解javaScript中的this到底是什么和它的词法作用域...

    最近,听到李笑来说,讲解编程的过程中,举例子很重要. 而且,我最近看的各种javaScript工具书中的例子,也都有点复杂. 所以啊,我试着举一些简单又直观的例子,与各位苦学javaScript的同学 ...

  5. javascript的词法作用域

    这个概念是js中相当基础也是极为重要的,很多想当然的错误或感觉怪异的问题都是和这个东西有关.所以,本文主要说下这个名词的概念以及讨论下他牵扯出来的有关变量.函数.闭包的问题. 由变量开始谈 习惯性先来 ...

  6. 你不知道的JavaScript之词法作用域

    词法作用域 总结一下作用域的定义:作用域就是一套规则,这套规则用于引擎如何进行查找变量以及在哪找到变量(可以看看之前我博客写的引擎和作用域之间的对话). 作用域分为词法作用域(也叫静态作用域)和动态作 ...

  7. JavaScript之词法作用域和动态作用域

    作用域 作用域是指程序源代码中定义变量的区域. 作用域规定了如何查找变量,也就是确定当前执行代码对变量的访问权限. JavaScript 采用词法作用域(lexical scoping),也就是静态作 ...

  8. javascript基础拾遗——词法作用域

    本来是想写js面向对象笔记(二)关于封装的,但是在敲实例代码的时候,发现对作用域这个东西的概念有点模糊,翻阅了犀牛后,有点感觉了,就想着先记录下此时的感受. 之所以取名叫做词法作用域,是这个概念是js ...

  9. 关于JavaScript的词法作用域及变量提升的个人理解

    关于JavaScript的作用域,最近听到一个名词:"词法作用域":以前没有听说过(读书少),记录一下对此的理解,加深印象. 词法作用域:在JavaScript中,一个函数的作用域 ...

最新文章

  1. 最强杀毒软件NOD32免费升级ID(保持最新)
  2. 如何通过编程方式添加Native Client服务器别名
  3. 解决alibaba-dubbo调用findFirstNonLoopbackHostInfo导致启动慢
  4. MySQL 优化器之Index merge Multi-Range Read MRR与Batched Key Access使用案例详解
  5. php通过条件来定义const,php用const出错是什么原因
  6. 高性能网站建设指南——网站优化的14条建议
  7. Java VisualVM无法检测到本地java程序 的 解决办法
  8. 洛谷——P1420 最长连号
  9. 解决引用flexible.js使第三方ui样式缩小的方法
  10. 中国水稻大省创新大米销售模式 启动2019首场拍卖
  11. MES系统最全介绍来了
  12. C++语言,线性素数筛(欧拉筛)
  13. 艺术创作六步法则、浅谈色彩、如何理解漫画
  14. 【springboot】启动流程之starting
  15. 冰箱10分钟启动一次_冰箱正常多久启动一次
  16. Solidity 安全:已知攻击方法和常见防御模式综合列表
  17. Atom同步设置、特效打字教程|基础插件
  18. Data truncation: Incorrect datetime value: ‘XXXX‘
  19. 不可忽视的UPS电源电池除尘
  20. 推荐几款实用软件工具

热门文章

  1. 使用MyEclipse开发Java EE应用:用XDoclet创建EJB 2 Session Bean项目(四)
  2. 软考中高项学员:2016年3月14日作业
  3. ci获取当前url链接的分组,控制器,方法
  4. 最后一个社团换届的感谢和感悟
  5. 数据结构之——队列与循环队列
  6. MySql - 索引
  7. ssm整合(基于xml配置方式)
  8. Java的三种代理模式简述
  9. 对Mapreduce代码进行单元测试
  10. hibernate02环境的搭建