zoukankan      html  css  js  c++  java
  • Javascript 链式作用域 function fn(){}和var fn=function(){}区别

    其实对于Javascript链式作用域的描述,包括,JS权威指南,都有些太冗长了--但是很准确:JavaScript中的函数运行在他们被定义的作用域里,而不是他们被执行的作用域里。

    这句话有点难懂,但程序的设计,基本都是为了简单,便于理解的。记住JS中经典的一句话是,一切皆对象。

    说白了链式作用域,其实就是Javascript的一个特性:子函数中可以访问父函数的所有变量。当然也包括全局变量window(一般的函数定义function a(){},其实都是window对象的子函数)。另外补充一下,函数定义有两种方式,其实略有差别:var a=function(){}和function a(){},稍后再解释他们的区别。

    所以,我们看Crockford的<<Javascript语言精粹>>中就提到,要在一个函数中定义变量,要养成良好的习惯,请直接在函数开头定义变量。JS中这点上有别于其它语言的要求----尽量推迟变量定义(使用前定义)。

    我们看一下laruence提供的例子:

    var name = 'laruence';
        functionecho(){
        alert(name);
        var name = 'eve';
        alert(name);
        alert(age);
        }

    echo();
        这个例子其实很有迷惑性(会让人错误的以为,输出结果是:laruence,eve,error;其实结果是:undefined,eve,error),关键就是因为echo()函数中定义的var name='eve'。但其实换个写法,这个例子就很清楚了:
     
        var name = 'laruence';
        function echo() {
        var name;
        alert(name);
        name = 'eve';
        alert(name);
        alert(age);
        }

    echo();


        其实,上面的函数在JS引擎解析的时候,就会被解析成这样。如果你是初学者,其实这样理解就可以了。但如果你有别的程序的编程经验,例如java。就很容 易被惯用思维给套住了,PS:本人就是给套住的一个。所以,还是按照Crockford的建议把,定义变量,请在函数顶部!!

     

    还记得之前的问题吗? var a=function(){}和function a(){}的区别。
     
        它们的区别还变量的定义比较类似。一切皆对象。
     
        他们两个在函数调用时,基本是等价的,但如果调用函数,在定义函数前就会有问题了。其实区别在于等号和function关键字。
     
        var和function定义在预编译的时候被提前,var只是占位,具体赋值要等到JS引擎执行到这行。而function定义会在JS引擎预编译阶段就被直接放入到调用对象中。
     
        还是要举例:
     
        例子一:

    alert( echo );//function echo(){return 1;};
        function echo(){return 1;};
        alert( a );//undefined
     
        var a=function(){return 1;};
     
        所以,函数的定义也可以引申出一句话,请将函数定义放在顶部(先定义后调用)!!

    其实还是习惯的问题,JS中一些代码的优良习惯有别于其它语言。建议大家读一下<<Javascript语言精粹>>。在开始学 习一门语言时,最好从欣赏优秀的代码开始。而JS中,大家都喜欢用一系列充满迷惑性的代码来加深自己的理解,这其实是一个误区。
     
        另外说一点,this关键字,laruence的解释很简洁到位:"谁调用,谁就是this"。英文版更详细一点:“In JavaScript this always refers to the “owner” of the function we're executing, or rather, to the object that a function is a method of. ”,中文解释:“在JavaScript中,this永远引用我们所执行函数的拥有者,更准确的说,this引用一个函数的方法对象”
     
        看看下面的例子,也是误导人的:
     
        function a(){
          g_value="uk";
        }
        a(); 
        alert(g_value);
     
        其实,比较友好的写法应该是这样:

     

    function a(){
        this.g_value="uk";
        }
        a();//a.apply(this);
        alert(this.g_value);
        关于this关键字,和别的语言也有区别。首先它并不是实例的引用,而是调用它的上下文。上面例子的a(),等价于a.apply(this);

    call和apply的用法是一样的,区别就在参数传递上。一个是一个一个传参数的,一个是将参数作为类数组传递的(注意这个地方是类数组)。

    用Javascript 两大特点,也是JS引擎的实现必然导致的:

    1) 返回值。在JS引擎中,所有的语法,操作都有返回值,而且通常返回值是它本身或undefined。通常我们可以用"()"操作符,来获取当前句子的返回 值(部分操作符不能用,如var)。例如:a=3;其实这行的返回值就是3,所以在a=b=3时,JS引擎就可以正确的执行下去,首先3赋值给b,然后当 前的返回值3再赋值给a(而不是大家所认为的,先将3赋值给b,然后再将b赋值给a)。又例如函数var fun=function(){},当JS引擎执行到这行时,会先执行右边,返回值是一个函数的字面量,然后将这个函数字面量赋值给fun。

    Jquery也是利用了这个特性(函数return this),所以才有链式调用。我们看个例子:"fontFamily".replace( /([A-Z])/g, "-$1" ).toLowerCase(),没错这里也是利用了返回值,所以这行的结果是:font-family。

    2) 闭包。子函数调用父函数的变量(非传参),就是闭包。在JS中,子函数能访问父函数的变量,这时被引用的变量不会释放,而且子函数中能一直持有这个变量的引用。

    结合以上两大特点,可以生成一个力量强大的怪胎:

    (function(){})();

    不知道专业的名称,我叫它为:立即执行匿名函数。

    首先在第一对括号内,是一个匿名函数,第二个括号会立即调用这个匿名函数的返回值,也就是匿名函数中的内容被立即执行。

    这个怪胎的强大在于,它独立了一个作用域(括号中内容执行完后会被立即回收),内部变量外部无法访问,而它又能通过this保留字,来访问外部变量。

    举个例子:

    var i=100;
        (function(){
        var j=1;
            this.plus_ij = function(){
            j+=i;
            alert(j);
            }
        }
    )
    ();
    plus_ij();

    plus_ij();

    上面的例子中,立即执行匿名函数,可以访问到外部变量i,甚至可以var定义一个i(也不会影响外部的i值)。而且内部变量j形成了一个闭包,不会释放。

    上一篇博文中介绍过function fn(){}和var fn=function(){},不过,那是在全局作用域中,如果我们将他们放到立即执行匿名函数中,会发生什么呢?

     

    (function(){
    var a = function(){}
    function b(){}
    this.c = function(){ a(); b(); }
    })();
    c();

     

    上面的例子,你会发现,无论哪种定义方式,在立即执行匿名函数外,都无法访问到a和b函数。也就是a和b函数成了这个立即执行匿名函数的内部函数,外部无法调用,除了通过这个立即执行匿名函数内部定义的外部函数。

  • 相关阅读:
    jenkins master-slave配置
    ansible-playbook 变量(vars)
    ansible-playbook && Roles && include
    ansible 循环与条件判断when
    python 微信爬虫实例
    JavaScript: 零基础轻松学闭包
    【干货】用大白话聊聊JavaSE — ArrayList 深入剖析和Java基础知识详解(二)
    【干货】用大白话聊聊JavaSE — ArrayList 深入剖析和Java基础知识详解(一)
    【大结局】《从案例中学习JavaScript》之酷炫音乐播放器(四)
    Java 实现批量重命名,亲测可用(精简版)
  • 原文地址:https://www.cnblogs.com/piuba/p/3341148.html
Copyright © 2011-2022 走看看