局部变量陷阱

先看一段代码:

  1. function foo() {
  2. var a = "hello"
  3. b = "world"
  4. return a + b;
  5. }

这个函数执行完成之后返回helloworld,结果确实没有问题。但是里面有一个细节就是两个局部变量一个前边有var,另一个没有。这似乎并不影响执行,但是事实上没有var的话,这个变量就变成了全局变量。你在这个函数外面调用一下alert(b)试一下就知道了。一个莫名其妙冒出来的全局变量在有时候会引起匪夷所思的bug,所以一定要记得局部变量声明前一定要用var

变量声明提升

再看一段代码:

  1. var foo = "hello"
  2. function test() {
  3. alert(foo);
  4. var foo = "world";
  5. }
  6. test()

代码执行时,请问alert的内容是什么呢?答案是undefined。从直觉上来讲,运行alert的时候,foo这个变量没有声明,不存在。既然局部作用域没有,那就去全局作用域找,应该是"hello"才是啊。为什么呢?这就是变量声明提升。函数内的任何变量的声明都会被提升至函数的顶部,所以上面的test函数相当于

  1. function test() {
  2. var foo;
  3. alert(foo);
  4. foo = "world";
  5. }

所以会是undefined。这里注意提升的只是声明,赋值的代码还在原来的地方。并且声明的部分与声明的代码是否执行无关,比如

  1. function test() {
  2. alert(foo);
  3. if(false) {
  4. foo = "world";
  5. }
  6. }

把test函数修改成这个样子,执行结果仍然是一样。声明仍然被提前了,尽管这行代码将不会被运行。
这就是变量声明提升,我们再看一个例子

  1. function test() {
  2. foo1();
  3. foo2();
  4. function foo1(){alert("foo1")}
  5. var foo2 = function(){alert("foo2")}
  6. }

当test函数执行的时候,结果如何呢?结果是foo1被alert出来,然后JS报错"undefined is not a function"。这里在函数内部声明函数的提升有点区别。foo1,用函数的方式声明定义一个函数,则声明与函数体都被提升了,但是foo2用变量的方式定义函数,被提升的只有声明,函数体没有被提升,所以执行foo2()的时候,foo2没有被赋值,是undefined。

看起来由于JS里面有变量声明提升,那么就无法使用C语言里面的块级作用域,那么我确实想用,怎么办呢?有一个办法是用匿名函数,举例如下:

  1. var foo = "hello"
  2. function test() {
  3. alert(foo);
  4. (function(){
  5. var foo = "world";
  6. })()
  7. }
  8. test()

当test函数改成这个样子的时候,alert出来的结果就是"hello"了,匿名函数里面的foo就无法作用到其他地方。

闭包中的局部变量

我之前招聘前端,问了应聘者这样一个题目,说请写一个可以返回递增整数序列的函数,他给我的答案是这样

  1. var i = 0;
  2. function increase() {return i++;}

当反复调用函数increase的时候,就会返回递增序列。但是我接着问,如果有人失手改了i怎么样,他语塞。其实这个问题的关键是说要制造一个很安全的地方来放置这个i,让这个变量只能被一个函数访问,所以一个可选的答案是这样。此时increase就是会返回递增序列。并且i放在了一个很安全的地方。就不会被破坏了。

  1. var increase = (function() {
  2. var i = 0;
  3. return function(){return i++;}
  4. })();

JS的闭包是一个很值得讲的内容,好用,但是也有不少坑,下面我专门开一篇文章来讲。

全局变量

无数讲高质量代码的书籍都会提到全局变量这个大杀器,程序员们都被反复告诫,除非你又充足的理由,否则不要使用全局变量,JS也不例外。然而JS有一个特殊的地方就是没有main方法,入口的代码一定要写,但是写在这地方的代码难免要用到变量,这些变量就是全局变量了,那么如何处理这个问题呢?答案还是匿名函数,像这样:

  1. (function(){
  2. var a = "a";
  3. var b = "b";
  4. var c = "c";
  5. foo(a, b, c);
  6. })()

把入口代码放到一个匿名函数中,这样这些变量a, b, c就会被藏到这个函数里面,就避免了全局变量的出现。

JavaScript 进阶(二)变量作用域的更多相关文章

  1. javascript中的变量作用域以及变量提升

    在javascript中, 理解变量的作用域以及变量提升是非常有必要的.这个看起来是否很简单,但其实并不是你想的那样,还要一些重要的细节你需要理解. 变量作用域 “一个变量的作用域表示这个变量存在的上 ...

  2. JavaScript基础——理解变量作用域

    一旦你开始在JavaScript应用程序中添加条件.函数和循环,就需要理解变量作用域.变量作用域规定了如何确定正在执行的代码行上的一个特定变量名的值. JavaScript允许你既定义全局版本又定义局 ...

  3. javascript中的变量作用域以及变量提升详细介绍

    在javascript中, 理解变量的作用域以及变量提升是非常有必要的.这个看起来是否很简单,但其实并不是你想的那样,还要一些重要的细节你需要理解变量作用域 “一个变量的作用域表示这个变量存在的上下文 ...

  4. 【JavaScript 从零开始】变量作用域

    变量作用域 一个变量的作用域(scope)是程序源代码中定义这个变量的区域. 全局变量拥有全局作用域,在JavaScript代码中的任何地方都是有定义的.然而在函数内声明的变量只是函数体内有定义. 他 ...

  5. JavaScript学习系列2一JavaScript中的变量作用域

    在写这篇文章之前,再次提醒一下 JavaScript 是大小写敏感的语言 // 'test', 'Test', 'TeSt' , 'TEST' 是4个不同的变量名 JavaScript中的变量,最重要 ...

  6. JavaScript要点 (一) 变量-作用域

    JavaScript 作用域 作用域—可访问变量的集合. 全局变量或者函数可以覆盖window对象的变量或者函数: 局部变量和window对象可以覆盖全局变量和函数. JavaScript 作用域 在 ...

  7. javascript中的变量作用域

    在网上看了一道js面试题 <script type="text/javascript"> var tt = 'aa'; function test() { alert( ...

  8. javascript痛点之一变量作用域

    1.用var声明的变量是有作用域的,比如我们在函数中用var声明一个变量 1 'use strict'; 2 function num(){ 3 //用var声明一个变量num1 4 var num1 ...

  9. 【Javascript系列】变量作用域

    问题描述 本篇文章主要讲解javascript变量及其作用域. 1   内容区 在js中,变量大致可分为全局变量(全局作用域)和局部变量(局部作用域): 用关键字var定义变量(全局变量,可以省略va ...

  10. Javascript入门(二)变量、获取元素、操作元素

    一.变量 Javascript 有五种基本数据类型 number.String.boolean.undefined.null 一种复合类型:object 二.使用getElementById方法获取元 ...

随机推荐

  1. 抽象工厂模式和autofac的使用总结

    抽象工厂模式和依赖注入的使用目的都是降低对象直接依赖耦合关系,应该说依赖注入是抽象工厂模式的一种升华,功能更强大. 说到抽象工厂的模式,一般都要先解释下简单工厂,简单工厂就是将对象的实例化抽取出来形成 ...

  2. ThinkPHP的验证码刷新显示和验证码显示不出来的原因

    1.应当这样<imp src='验证码路径' onclick="this.src='验证码路径?'+Math.random()">;如果后面不加Math.random( ...

  3. libev源代码浅析

    libev是一个开源的事件驱动库,基于epoll,kqueue等OS提供的基础设施.其以高效出名,它可以将IO事件,定时器,和信号统一起来,统一放在事件处理这一套框架下处理. libev的基本使用方法 ...

  4. PHPExcel用法

    <?php //下面是总结的几个使用方法 include 'PHPExcel.php'; include 'PHPExcel/Writer/Excel2007.php'; //或者include ...

  5. <转> 30 个有关 Python 的小技巧

    目录[+] 1.1 拆箱 1.2 拆箱变量交换 1.3 扩展拆箱(只兼容python3) 1.4 负数索引 1.5 切割列表 1.6 负数索引切割列表 1.7指定步长切割列表 1.8 负数步长切割列表 ...

  6. Clojure学习05:谓词函数

    谓词函数是一个判断式,一个返回bool值的函数. clojure中(lisp习惯)有个规定:对于判断功能的函数,函数名后面都有一个“?”号.所以只要看到后面带问号的函数名,就知道这一定是一个判断函数. ...

  7. 基于visual Studio2013解决C语言竞赛题之0517矩阵

     题目

  8. 0-1背包的动态规划算法,部分背包的贪心算法和DP算法------算法导论

    一.问题描述 0-1背包问题,部分背包问题.分别实现0-1背包的DP算法,部分背包的贪心算法和DP算法. 二.算法原理 (1)0-1背包的DP算法 0-1背包问题:有n件物品和一个容量为W的背包.第i ...

  9. C语言之基本算法09—各位全是a的数列之和

    /* ================================================================== 题目:数列为a,aa,aaa,--.求a+aa+aaa+-- ...

  10. 设置不输入密码ssh登录

    在/etc/hosts文件下加入: 192.168.1.60 u60 #设置u60为主机名 在每个节点上创建RSA秘钥: # ssh-keygen -t rsa # 一直按确定键即可 # touch ...