zoukankan      html  css  js  c++  java
  • JavaScript 进阶(二)变量作用域

    局部变量陷阱

    先看一段代码:

    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就会被藏到这个函数里面,就避免了全局变量的出现。

  • 相关阅读:
    octotree神器 For Github and GitLab 火狐插件
    实用篇如何使用github(本地、远程)满足基本需求
    PPA(Personal Package Archives)简介、兴起、使用
    Sourse Insight使用过程中的常使用功能简介
    Sourse Insight使用教程及常见的问题解决办法
    github 遇到Permanently added the RSA host key for IP address '192.30.252.128' to the list of known hosts问题解决
    二叉查找树的C语言实现(一)
    初识内核链表
    container_of 和 offsetof 宏详解
    用双向链表实现一个栈
  • 原文地址:https://www.cnblogs.com/mafeng/p/6292535.html
Copyright © 2011-2022 走看看