首先介绍下Javascript的函数作用域的概念,然后了解下什么是作用域和声明提前,最后通过一个例子剖析Javascript的作用域链。

1.变量的作用域

稍微有些编程背景的都知道,变量的作用域分为两种: 全局变量 和 局部变量 。

Javascript是一门 弱类型语言 。所有的变量声明都是通过var来接收,如

  1. var num = 1;
  2. var str = “string”;
  3. var flag = true;

看似是一个非常省事的机制,但是也有让人头疼的时候,一些隐式的类型转换经常会把搞晕。先看看全局变量和局部变量:

  1. var g = "global"; function f(){ var l = "local";
  2. }

注意 : 1. 如果在函数f()中将去掉var声明,则变量l就会从局部变量升级为全局变量。

2. 局部变量的优先级高于同名的全局变量 。如果在函数f()中声明一个局部变量也为g,则全局变量就会被局部变量覆盖

2.作用域和声明提前

看到Javascript作用域这块,可以说颠覆了以前我对作用域的认识。类似Java和C等编程语言,在花括号“{}”内的代码都是有各自的作用域的,并且在这个范围以外,这些变量是不可见的,我们称这种作用域为 块级作用域 。

但是这完全不适用于Javascript,因为Javascript没有块级作用域,但是Javascript有 函数作用域 。函数作用域简言之就是:变量在声明他们的函数体以及这个函数体嵌套的任意函数体内都是有定义的。

对于“ 变量在声明他们的函数体以及这个函数体嵌套的任意函数体内都是有定义的 ”这句话的延伸理解:变量在声明之前就已经可用。我们称这种特性为声明提前,也就是函数里的所有变量都被“提前”至函数体的顶部。

下面我们看一个经典的陷阱案例:

  1. var v = "yoyo"; (function(){ console.log(v); var v = "check now";
  2. console.log(v);
  3. })();

对于第二次执行结果“check now”没有什么特别的,为什么第一次输出的不是“yoyo”而是“undefined”。

对于这个问题的解释就用到上面的那句话, 局部变量在整个函数体始终是有定义的 ,即在函数体内局部变量覆盖了同名全局变量,而且,程序只有在执行到var语句时,局部变量才会被真正赋值。所以,这时你大概会明白为什么是undefined了,因为此时还没有遇到var,即没有定义,等价于下面的形式:

  1. var v = "yoyo"; (function(){ var scope; console.log(v); var v = "check now";
  2. console.log(v);
  3. })();
  4. 疑问 ? ? ?
  5. 将上面的代码稍稍修改为:
  6. var v = "yoyo"; (function(){
  7. console.log(v);
  8. })();

运行结果为:

相比于上面的代码只是少了一行添加一个局部变量v并赋值的语句,但是结果却是“yoyo”。

这里之所以输出“yoyo”,不能按照上面的定式思维。上面有句话叫“局部变量在整个函数体始终是有定义的”,但是这里没有局部变量的定义,所以按照下面要提到的作用域链会逐层向上寻找变量,最后找到了全局变量v,从而最后的输出是“yoyo”。

举一个通俗点的例子,你准备要花钱买点东西时,会先摸摸自己的钱包,没了你可以找你爸要,你爸也没有就再找你爷爷,... 。而你爸没钱买东西时,他并不会来找你要。

以上是我的个人理解,如果你对这两种情况有自己的理解,请在下方给出,望不吝指教。

3.作用域链

全局变量在程序中始终是有定义的,局部变量在声明它的函数体内以及其所嵌套的函数内始终是有定义的。

每一段Javascript代码(全局代码或函数)都有一个与之相关联的作用域链,这个作用域链就是一个对象列表或链表。比如当 Javascript需要查找变量x的值时,它会从链中的第一个对象开始,如果该对象有一个名为x的属性,则直接使用,如果不存在名为x的属性,则会继续 向链上的下一个对象查找,如此递归下去直到找到。如果整个链上都找不到,则认为不存在x这个属性。举例:

  1. name="lwy"; function t(){ var name="tlwy"; function s(){ var name="slwy"; console.log(name); } function ss(){ console.log(name); } s();   ss();
  2. }
  3. t();

JS的作用域和声明提前的更多相关文章

  1. JavaScript权威设计--JavaScript变量,作用域,声明提前(简要学习笔记四)

    1.宿主对象与宿主环境 宿主对象:由ECMAScript实现的宿主环境提供的对象,可以理解为:浏览器提供的对象.所有的BOM和DOM都是宿主对象.   宿主环境:一般宿主环境由外壳程序创建与维护,只要 ...

  2. 【翻译】JavaScript中的作用域和声明提前

    原文:http://www.adequatelygood.com/JavaScript-Scoping-and-Hoisting.html ===翻译开始=== 你知道下面的JavaScript脚本执 ...

  3. JavaScript中的作用域和声明提前

    [翻译]JavaScript中的作用域和声明提前 原文:http://www.adequatelygood.com/JavaScript-Scoping-and-Hoisting.html ===翻译 ...

  4. JavaScript函数作用域和声明提前(3.10.1 page.57)

    <h4>3.函数作用域和声明提前</h4> <p> <!--<script type="text/javascript">-- ...

  5. javascript中函数作用域和声明提前

    javascript不像java等其他强类型语句,没有块级作用域(括号内的代码都有自己的作用域,变量在声明它们的代码段之外不可见)一说,但有自己的独特地方,即函数作用域. 函数作用域:变量在声明它们的 ...

  6. js函数中变量声明提前

    <!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8" ...

  7. js 中的变量声明提前总结

    一.var 声明 ES6之前,js 中声明变量基本上用 var 关键字: 1.如果访问未声明的变量,会报错:ReferenceError 2.声明了未赋值,值为 undefined,跟前面的报错是两回 ...

  8. javascript中的函数作用域和声明提前

    在一些类C的编程语言中,花括号内的每一段代码都具有各自作用域,并且变量在声明他们的代码段之外是不可见的,这个概念叫做块级作用域. javascript中没有块级作用域的概念,有的是函数作用域的概念:变 ...

  9. 前端面试题总结一(js变量和函数声明提前相关)

    好久没有更新博客了,^_^写写博客吧!下面是我总结的一些面试题,希望对大家有所帮助 (1)题目如下: alert(a)  var a=1  function a(){    alert(a) } 好多 ...

随机推荐

  1. delphi 6数据库连接之长短模式(sqlserver)

    delphi 6数据库连接之长短模式(sqlserver) 标签: delphi数据库 2015-08-12 20:59 351人阅读 评论(0) 收藏 举报  分类: delphi(3)  版权声明 ...

  2. Java动态绑定与静态绑定

    Java动态绑定来自于继承体现,子类继承父类,子类重新覆盖了父类的方法,就是动态绑定,以下举例: (动态绑定是在运行期间) 动物类: /** * 创建一个动物类 * @author Liudeli * ...

  3. Ubuntu14.04下Pycharm3.4 字体渲染

    在ubuntu下搭建了django的开发环境,搭建过程十分简单,Pycharm的安装更简单,下载tar包解压并执行bin目录下的脚本即可,但是看着那个字体真心不爽.于是开始搜索调教. 1.安装打了渲染 ...

  4. DBCC--常用命令

    ------------------------------------------------------ --1 DBCC FLUSHPROCINDB 清除SQL SERVER服务器内存中某个数据 ...

  5. 记录.NET Core部署到Linux之发布项目到Linux(2)

    1.选择文件夹发布项目到本地,通过Xftp上传文件到/home/wwwroot下:下面具体介绍下 2.通过Xftp直接拖拽压缩包到linux下,通过命令cd /home/wwwroot目录下;然后输入 ...

  6. C#如何关闭指定进程

    public static void KillProcess(string strProcessesByName)//关闭线程 { foreach (Process p in Process.GetP ...

  7. Wpf 导出CSV文件

    /// <summary> /// 将DataTable中数据写入到CSV文件中 /// </summary> /// <param name="dt" ...

  8. 消息中间件(Kafka/RabbitMQ)收录集

    https://blog.csdn.net/u013256816/article/details/54743481

  9. hdu4815----dp0-1背包

    /* 题目大意: 有n个问题,,告诉你答对该题能得多少分,其中一个人随机答题,问另一个人不输的概率为p 至少需要答多多少分 对于样例: 3 0.5 1 2 3 分析: 分数 0 1 2 3 3 4 5 ...

  10. nginx-限制后端服务器连接数

    http加 limit_conn_zone $binary_remote_addr zone=perip:10m;limit_conn_zone $server_name zone=perserver ...