专栏首页JackieZheng初探JavaScript(四)——作用域链和声明提前

初探JavaScript(四)——作用域链和声明提前

前言:最近恰逢毕业季,千千万万的学生党开始步入社会,告别象牙塔似的学校生活。往往在人生的各个拐点的时候,情感丰富,感触颇深,各种对过去的美好的总结,对未来的展望。与此同时,也让诸多的老“园”工看完这些小年轻的文章后感触良多,不禁也要写上几笔,所以就出来了很多类似“毕业两年小记”、“毕业五年有感”……

  可能就是某篇博文的一句话,某碗心灵鸡汤就拨动了你心里的那根尘封已久的弦,让你情不自禁的点了个赞,还忍不住的要在下面评论区留下自己此刻心潮澎湃的印记。

我今天不是来送鸡汤的,鸡汤虽好,可不要贪杯哦。

正文

  截止上一篇关于Javascript的博文《初探JavaScript(三)——JS带我"碰壁"带我飞》已经写了三篇。前三篇主要是从一名纯小白的角度,结合《Javascript DOM编程艺术》这本书记录下自己的一些总结和感悟。

  大致的翻完《Javascript DOM编程艺术》后,感觉自己了解肯定还是太浅了,因为当时对于”原型”、”闭包”等这些完全没概念,我知道我缺的还很多。于是,我又伸出双手,接过另外一部经典之作《Javascript权威指南》,继续Javascript之行。

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

1.变量的作用域

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

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

var num = 1;
var str = “string”;
var flag = true;

  看似是一个非常省事的机制,但是也有让人头疼的时候,一些隐式的类型转换经常会把搞晕,这里不做展开,后面有时间可以单独开一篇详谈。先看看全局变量和局部变量:

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

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

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

2.作用域和声明提前

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

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

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

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

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

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

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

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

疑问???

将上面的代码稍稍修改为:

var v = "yoyo";
(function(){
    console.log(v);
})();

  运行结果为:

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

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

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

3.作用域链

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

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

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

  如果对你有用,欢迎点赞^_^

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Nutch源码阅读进程1---inject

    最近在Ubuntu下配置好了nutch和solr的环境,也用nutch爬取了一些网页,通过solr界面呈现,也过了一把自己建立小搜索引擎的瘾,现在该静下心来好好...

    JackieZheng
  • Spring集成RabbiMQ-Spring AMQP新特性

    上一篇《Spring集成RabbitMQ-使用RabbitMQ更方便》中,我们只需要添加响应jar的依赖,就可以写一个Spring集成RabbitMQ下非常简单...

    JackieZheng
  • 漫谈可视化Prefuse(一)---从SQL Server数据库读取数据

      上篇《可视化工具solo show-----Prefuse自带例子GraphView讲解》主要介绍了整个Prefuse工具集具有的一些特征、框架的运行流程,...

    JackieZheng
  • JavaScript闭包原理与用法实例

    (1)变量的作用域 不带有关键字var的变量会成为全局变量; 在函数中使用关键字var声明的变量是局部变量。 局部变量只有在函数内部才能访问到,在函数外面是访问...

    Javanx
  • JavaScript闭包

    函数和对其词法环境lexical environment的引用捆绑在一起构成闭包,也就是说,闭包可以让你从内部函数访问外部函数作用域。在JavaScript,函...

    WindrunnerMax
  • python3第五天(条件,循环,函数)

        可以对迭代对象进行for循环,也可以用next来访问迭代对象中的下一个元素.

    py3study
  • iOS· UIGestureRecognizer 与UITouch 的 locationInView方法含义区别

    UIGestureRecognizer 与UITouch 都有一个 locationInView: 方法。

    陈满iOS
  • Java集合深度解析之TreeMap

    红黑树简介 TreeMap是基于红黑树实现的,这里只对红黑树做个简单的介绍,红黑树是一种特殊的二叉排序树,红黑树通过一些限制,使其不会出现二叉树排序树中极端的一...

    互扯程序
  • Java集合-TreeMap源码解析-JDK1.8

    TreeMap在jdk 1.8中使用用的是红黑树的结构来进行存储的,一个典型的红黑树就如下图所示:

    Java学习录
  • python面向对象之反射

    类方法:有个默认参数cls,并且可以直接用类名去调用,可以与类属×××互(也就是可以使用类属性)

    py3study

扫码关注云+社区

领取腾讯云代金券