zoukankan      html  css  js  c++  java
  • JavaScript中的作用域

    【转载】

    1、定义

    作用域scope
    1)某样事物执行、操作、拥有控制权的那么一个区域
    2)编写程序时,程序之中变量的可见度;例如,一个函数能否使用另外一个函数所创建的变量。

    2、例子演示

    打开firefox,弹出firebug,点击console tab。在Firefox状态栏上面看到有>>>提示的地方就可以输入了。

    function fn(){alert(11);}

    然后回车。一切安然...你刚才做的实际上是定义了一个函数fn。接着试试:

    fn();

    然后回车。得到11的警告窗口,接着试试:

    window.fn();
    this.fn();

    得到一样的结果吧?这是因为函数fn是window对象的一个方法,在第二行的"this"的作用域实际指向了window对象。不过多数情况中你不需要像这样window.myFunction(...)地调用函数,这样太麻烦了,程序员工作起来会很不方便。

    window对象

    window 对象总是存在的,你可理解其为一个浏览器窗口对象。它包含了其它所有的对象如document 和所有的全局变量。

    你可以打开Firebug,切换到 Script 页面并在Firebug右侧的New watch expression... 里面输入window。观察window对象究竟有什么在里面。

    接着,尝试找出我们之前定义过的fn函数。

    另外,每个frame或iframe拥有其自身的window对象,其自身的全局空间。

    理解作用域

    接下的内容开始有点复杂了。切换到Firebug Console标签页然后输入:

    var o1 = {testvar:22, fun:function() { alert('o1: ' + this.testvar); }};
    var o2 = {testvar:33, fun:function() { alert('o2: ' + this.testvar); }};

    结果是什么?你声明了o1o2两个对象,分别都有一些属性和方法,但值不同。

    接着试试:

    fun();
    
    window.fun();
    
    this.fun();

    出错了,是吧?因为window对象(等价于this)并没有fun的方法。试一试下面的:

    o1.fun();
    o2.fun();

    22和33出来了?非常好!

    接下来这部分的内容最复杂啦。基于这个原始的函数,如果对象的数量多的话,你必须为每个对象加上这个函数-明显是重复劳动了。这样说吧,o1.fun写得非常清晰的而且为了搞掂它已经占用了我一个星期的开发时间。想象一下代码到处散布着this变量,怎么能不头疼?如果要将调用(执行)的o1.fun方法但this会执行o2,应该怎么实现呢?试一试下面的:

    o1.fun.call(o2);

    明白了吗?当执行o1的fun方法时你强行将变量this指向到o2这个对象,换句话说,更加严谨地说:o1.fun的方法在对象o2的作用域下运行。

    当运行一个函数,一个对象的方法时,你可将作用域当作this值的变量

    变量的可见度

    变量的可见度和作用域的关系非常密切。我们已经了解到,可在任何对象的外部,声明变量,或在全局的函数(函数也是变量的一种)也可以,更严格说,它们是全局对象window的属性。 全局变量在任何地方都可见;无论函数的内部还是外部。如果你在某一个函数内修改了一个全局变量,其它函数也会得知这个值是修改过的。

    对象可以有它自己的属性(像上面的testvar),这些属性允许从内部或是外部均是可见的。试:

    alert(o1.testvar); // 从外部访问o1的属性testvar

    从内部访问的演示可在两个测试对象的fun方法找到。

    用关键字var在内部声明,相当于声明局部变量(局部声明也是在一条链上,即Scope Chain 作用域链上):

    i = 44; 
    function fn2() { 
        var i = 55; 
        alert(i); 
    }
    fn2();

    将得到什么?对了,55。声明在函数fn2的变量i是一个本地变量(局部变量),和等于44的全局变量i 44没什么关系。But:

    alert(i); 

    这会访问全局变量i,显示44。

    二.嵌套的函数(作用域链)

     1 var testvar = 'window属性';     
     2 var o3 = {
     3        testvar:'3',
     4        testvar2:'999',
     5        fun:function(){
     6           alert('o3: '+this.testvar);//'o3 3'
     7           var inner = function(){
     8               //当前对象的作用域+全局作用域 :闭包
     9              alert('o3-inner: '+this.testvar); //可以改成o3.testvar试下结果
    10              alert('o3-inner: '+this.testvar2);
    11              alert('o3-inner: '+testvar);        
    12           };
    13           inner();        //window
    14           //inner.call(this);    //o3+window
    15           //inner.call(o2);    //o2+window
    16        }
    17     };
    18     o3.fun();//可以调用非o3声明的成员变量

    这里我们换了别的函数,这个函数与原先的函数几乎相似但区别是内部函数的写法。要注意的是内部函数运行时所在的作用域,和外部函数的作用域是不一样的。Ext可让你调用函数时指定函数的作用域,避免作用域的问题。

    在此也先提一下闭包:闭包,指的是词法表示包括不被计算的变量的函数,也就是说,函数可以使用函数之外定义的变量(相信面试时好多小伙伴都会被问到闭包)

    变量的声明

    初始化变量时一定要加上“var”关键字,没有的话这就是一个全局变量。譬如,在下面的例子中,会有一个变量写在函数内部,然而你打算仅仅是声明局部的变量,但实际也可能出现覆盖全局变量的值的情形。在FIREBUG "DOM"的标签页中,你可通过检测“window”看到所有的全局变量。如果你发现有“k”或“x”变量那证明你把这个变量分配在一个不合适的作用域里面。见下例:

    var i = 4;
    var j = 5;
    var k = 7;
    var fn = function(){
       var i = 6;
       k = 8;//注意前面没有var 所以这句话的意思的把8赋予到变量k中去!
       alert(i);//6
       alert(j);//5
       alert(k+'-1');//8-1
       x = 1;//这句的作用有两种情况,创建全部变量x或覆盖(overwrite)全部变量x
    };
    fn();
    alert(k+'-2');//8-2 (注意不是7-2)

    与前面例子变化不大,另外注意的是函数内的k前面是没有var关键字的,所以这里不是声明局部变量,而是将某个值再次分配到k这个全局变量中。另外要注意的是,alert方法执行期间,参数i是当前能找到的局部变量,它的值是6,但参数j在当前作用域找不到,就沿着作用域链(scope chain向上查找,一直找到全局变量的那个j为止。

    总结:

    1. 一切成员的作用域均为window
    2. 对象的作用域可以通过call传递
    3. 函数内部的变量声明:带var的为局部变量,不带的则为全局变量.
    4. 函数内部声明的函数,默认作用域指向window.
  • 相关阅读:
    Centeos7搭建selenium+Chrome浏览器
    数据结构学习篇之栈和队列
    数据结构学习篇之线性表
    Tornado基础学习篇
    Python控制函数运行时间
    python线程实现异步任务
    Python实现几种简单的排序算法
    python爬虫遇到会话存储sessionStorage
    Python 有哪些优雅的代码实现让自己的代码更pythonic?
    Ubuntu查看端口使用情况,使用netstat命令:
  • 原文地址:https://www.cnblogs.com/humanxiaoman/p/5022419.html
Copyright © 2011-2022 走看看