zoukankan      html  css  js  c++  java
  • JavaScript学习系列2一JavaScript中的变量作用域

    在写这篇文章之前,再次提醒一下

    JavaScript 是大小写敏感的语言

    // 'test', 'Test', 'TeSt' , 'TEST' 是4个不同的变量名

    JavaScript中的变量,最重要的就是它的作用域, JS中变量的作用域其实就是函数作用域

    比如我们的浏览器,在JavaScript中,它就是一个被实例化的window对象, 如果我们在window下面定义一个name字段, 那么name字段就具有window这个函数的作用域, 也就是说在整个window下面是可以访问这个name字段来获取它的值的

    那现在我们在window下面定义一个函数Function MyFunc, 然后在这个函数里面定义了一个变量myName, 那么这个新定义的变量myName,它的作用域就是在函数MyFunc里面,也就是说只能在MyFunc函数中才可以访问myName变量

    上面是在Chrome=》F12的Console中的一个例子. 刚写的时候一直报错,后来发现是我把function写成了Function,第一个字母大写了,就报错

    现在我们换一种方式来写,看看会出现什么情况

    这里,我们做了一下更改,在函数MyFunc中,在定义name变量之前,就使用console.log(name)语句来输出name, 如果没有在Chrome的console中执行的话,我可能会误以为它应该输出windowName. 因为这个时候,在函数MyFunc中还没定义name, 而全局变量(window对象下的变量)中已经定义了一个name="windowName", 所以我觉得它应该获取全局变量的值。但实际呢,我们可以看到,在实际中它输出的是undefined, 这是怎么个情况呢?

    原来JavaScript的解析器在执行函数MyFunc的时候,第一件事情就是寻找这个函数中的所有局部变量,然后再执行后续语句, 所以它会先找到在函数MyFunc中定义了局部变量name, 但既然找到定义了局部变量name,为什么没有取到它的值funcName呢。 而是输出undefined呢。 这是因为解析器虽然先会寻找函数中的所有局部变量,但是在执行语句时,还是一条一条来执行的,所以解析器先找到函数MyFunc中已经定义了局部变量name,然后执行时,一条一条语句来执行

    执行第一条语句 console.log(name);  => 此时,发现MyFunc函数中已经定义了局部变量name,但是此时还没有给它赋值,所以得到的就是undefined.  

    这一点也可以如下解释 JavaScript在解析代码的时候,都会搜索一下var声明的变量,然后将其声明提前。 javascript这个特性被非正式地称为 声明提升(hoisting)

    所以,如下语句

    alert(name);  // 这里弹出undefined
    var name = "Luke";

    它实际的解析过程如下:

    var name;
    alert(name);  // 这里弹出undefined
    name = "Luke";

     那么,我们在换一种写法,来看看

    在这里,我们首先定义了一个全局变量name="windowName", 然后在函数中,有一行语句

    name="funcName"

    注意,这里不是var name = "funcName", 也就是说它并不是在函数MyFunc中定义一个新的变量var name, 而是重新给全局变量name赋值,把它的值由windowName改为了funcName

    所以JavaScript解析器在执行MyFunc函数这段代码时,先会去找这个函数内部的局部变量,发现没有。所以执行console.log(name);语句时,获取的就只能是全局变量name的值,这里就是windowName

    接下来name="funcName", 将这个全局变量name的值由windowName改为了(重新赋值)funcName, 所以在MyFunc()之后执行console.log(name),输出的是全局变量name中的新值 funcName

    我们再来看两个相似的例子

    var testList = [11,12,13];
    function myShow(){
    
     if(typeof testList === 'undefined')
     {
          testList = [];
     }
    
    alert(testList.length);
    
    };
    
    myShow();//结果 3

    这里结果将输出3,因为在这个例子中,在函数myShow中没有定义testList(var testList), 所以JavaScript编译器找的就是全局变量testList,显然,它的length就是3

    再看下面

    var testList = [11,12,13];
    function myShow(){
    
     if(typeof testList === 'undefined')
     {
         var testList = [];
     }
    
    alert(testList.length);
    
    };
    
    myShow(); //结果 0

    注意到在函数myShow中,var testList是在myShow函数内部的if语句块中定义的。 这里要注意一下

    JavaScript中没有块级作用域(由{}限定的作用域), 函数中声明的变量,无论在函数内部的哪一个地方声明,在这整个的函数中都是有定义的,都是一样的效果。

    所以,这里,实际的执行过程是这样的:

    var testList = [11,12,13];
    function myShow()
    {
       var testList;
     
    if(typeof testList === 'undefined')
     {
         testList = [];
     }
    
    alert(testList.length);
    
    };
    
    myShow(); //结果 0

    所以在执行函数myShow时,发现定义了和全局变量testList同名的局部变量,此时还没给它赋值,所以确实是undefined, 所以执行if条件中的语句, testList = [], 它的length就是0

    接下来,我们来看看函数定义式函数表达式之间的区别

    函数定义式  function show(){} 采用这种函数定义式的声明方法,函数的定义会提前

    函数表达式 var show = function(){}  函数的表达式,和普通的JavaScript变量的处理是一样的,也就是说函数声明会提前,但函数定义的位置不变

    我们来看下面两个例子

    alert(typeof myFunc);  //输出结果: function
    function myFunc(){}

    JavaScript在解析代码时, 像function myFunc()这种函数定义,和var声明定义变量一样,都会被提到前面。不同点在于:

    var声明定义变量时,只会把var声明提到最前面,而定义还会停留在原处

    而函数定义function myFunc(),函数声明和定义是一起的,都会同时被提到前面。所以上面的语句和下面执行是一样的

    function myFunc(){}
    alert(typeof myFunc);  //输出结果: function

    那我们再来看函数表达式的例子

    alert(typeof myFunc); //输出: undefined
    var myFunc = function(){};

    这个执行起来就是下面这样的

    var myFunc;
    alert(typeof myFunc); //输出: undefined
    myFunc = function(){};

     我们再来看两个更容易出错更让人抓狂的例子

    var myData = {name:'testName'};
    function myData()
    {
       alert('testName function');
    }
    myData();   //输出 TypeError: object is not a function

    这个例子非常抓狂吧,这里很容易以为是输出"testName function". 这个确实是很难辨别的一个例子

    我们前面说过,var声明定义的变量会把声明提前,通过function myFunc(){}这种函数定义的函数会把函数的声明和定义同时提前. 这里就是这种情况,两个都会提前,那到底谁更前呢? 注意

    var声明定义变量和函数定义同名时,函数的声明定义会在更前面,所以上面的JavaScript执行时会变成如下:

    function myData()
    {
       alert('testName function');
    }
    var myData;
    myData = {name:'testName'};
    
    myData();   //输出 TypeError: object is not a function

    可以看出,myData此时不再是函数,所以你不能采用这种方法myData(), 所以报错

    那我们再看下面这个例子

    var myData = {name:'testName'};
    var myData = function()
    {
       alert('testName function');
    }
    myData();   //输出结果: testName function

    在这里函数是通过函数表达式(而不是函数定义式)的var形式来声明定义的,而前面的变量var myData = {name:'testName'}也是var形式,两个优先级是一样的,所以就按代码顺序来,实际执行过程如下

    var myData;
    myData = {name:'testName'};
    myData = function()
    {
       alert('testName function');
    }
    myData();   //输出结果: testName function

    上面的例子就是这样,JavaScript的变量是一个非常绕的事情, 我们再来看一个例子

    alert(name);  //报错: 对象未定义, 使用一个压根就不存在的变量,所以出错
    
    age = 24; //这里有错吗,这里不会报错,为什么呢?  
                   //  JavaScript中给一个未定义的变量赋值,就会自动创建一个全局变量, 这就
                       相当于 var age = 24

     

  • 相关阅读:
    垂死挣扎还是涅槃重生 -- Delphi XE5 公布会归来感想
    自考感悟,话谈备忘录模式
    [每日一题] OCP1z0-047 :2013-07-26 alter table set unused之后各种情况处理
    Java实现 蓝桥杯 算法提高 p1001
    Java实现 蓝桥杯 算法提高 拿糖果
    Java实现 蓝桥杯 算法提高 拿糖果
    Java实现 蓝桥杯 算法提高 求arccos值
    Java实现 蓝桥杯 算法提高 求arccos值
    Java实现 蓝桥杯 算法提高 因式分解
    Java实现 蓝桥杯 算法提高 因式分解
  • 原文地址:https://www.cnblogs.com/wphl-27/p/9327062.html
Copyright © 2011-2022 走看看