zoukankan      html  css  js  c++  java
  • Function Declaration与Function Expression

    区分变量与对象

    在讨论函数声明与函数表达式之前,我觉得有必要明确一下JavaScript中变量及对象的区别。具体来说:

    JavaScript中的对象(Object)是一个实体,而变量(Variable)仅仅是一个用于保存值或对对象引用的符号(Symbol)。JavaScript的变量是松散类型的,这意味着变量符号可以任意指向不同类型的数据。

    混淆变量与对象,常常会造成误用。例如在与一位朋友的讨论中,他写下如下代码试图切断原型链:

    function func(){
    }
    func.prototype = null; //变量func.prototype变为null,但其之前引用的对象仍存在
    var o = new func();
    alert(null === o.__proto__) //false

    这位朋友的本意是将func的原型对象销毁,但是func.prototype = null一句并不能达到其目的,因为func.prototype只是JavaScript解释器提供给用户的一个以只读方式访问原型对象的指针符号,将其设为null,只是令这个符号不引用任何对象了,但实际func的原型对象并未被销毁。下图是对此原理的一个图示,虚线表示被切断的引用。

    image

    而且,func构造对象时并不是通过func.prototype去访问其原型,而是通过一个用户不可见的内部引用(具体实现依赖于解释器,上图假设为_proto)去访问的。这就好比C语言中只将指针置为null是不能释放内存一样,下面用一段C代码类比上面的过程:

    Function* func = (Function*)malloc(sizeof(Function));
    func->inner_proto = (Prototype*)malloc(sizeof(Prototype)); //此指针对用户不可见,供解释器内部使用
    func->prototype = func->inner_proto; //此指针提供给用户
      
    func->prototype = null; //因此这样操作并不能销毁func的原型对象

    JavaScript这一点和PHP很类似,熟悉PHP的朋友应该知道,PHP对变量的内部表示是一个zval结构体,JavaScript中的对象就相当于zval,而PHP中的变量同样是一个松散类型的符号,因此在PHP中单纯将变量设置为null并不能销毁其引用的变量,如需销毁需要显示使用unset或依靠GC机制。例如:

    class foo{}
    $bar  = new foo;
    // unset($bar); 如果这样可以立即销毁对象
    $bar = NULL; 单纯使用此语句不能立即销毁$bar引用的对象,如果此对象没有其它引用,则需要等待GC机制销毁

    与PHP不同的是,几乎所有JavaScript解释器都不提供与PHP中unset对应的显式销毁对象的方法,因此需要等待GC机制进行垃圾回收时才能将不再用的对象销毁。

    Function Declaration与Function Expression

    Function Declaration与Function Expression在绝大多数情况下没有区别,唯独的区别在创建Function对象的时机上。先看下列两段代码:

    代码A:

    //Function Declaration
      
    sayHello(); //Hello!
      
    function sayHello(){
        alert('Hello!');
    }

    代码B:

    //Function Expression
      
    sayHello(); //TypeError: undefined is not a function
      
    var sayHello = function(){
        alert('Hello!');
    }

    这两段代码几乎是一样的,但是使用函数声明的代码A运行正常,而使用函数表达式的代码B则会报错。这是因为以下事实:

    JavaScript是一种解释型语言,函数声明会在JavaScript代码加载后、执行前被解释,而函数表达式只有在执行到这一行代码时才会被解释。

    所以代码A相当于在执行sayHello()前已经建立了一个Function Object并赋给了变量sayHello,其对应代码如下:

    var sayHello = new Function("alert('Hello!')");
    sayHello();

    而代码B在执行sayHello()还未存在Function Object和变量sayHello,因为JavaScript在第一次使用某变量时会建立此变量,所以此处建立变量sayHello,但其值时undefined,未引用任何对象,将其作为函数来调用当然会出错。另外,解释JavaScript时如果某个变量已经存在,则其前面的“var”关键字被忽略,所以B代码等价于下列代码:

    sayHello = undefined;
    sayHello(); //TypeError: undefined is not a function
    sayHello = new Function("alert('Hello')");

    除了什么时候可以被访问到外,JavaScript中的Function Declaration与Function Expression两种语法其实是等价的。另外,大多数浏览器支持将两种语法一起使用,如:

    //除Safari外正确
    var func = function func(){
    }

    但是以上语法在Safari上会报错。因此为了浏览器兼容性考虑,任何时候都不要合并使用两种语法。

  • 相关阅读:
    PAT顶级 1015 Letter-moving Game (35分)
    PAT顶级 1008 Airline Routes (35分)(有向图的强连通分量)
    PAT顶级 1025 Keep at Most 100 Characters (35分)
    PAT顶级 1027 Larry and Inversions (35分)(树状数组)
    PAT 顶级 1026 String of Colorful Beads (35分)(尺取法)
    PAT顶级 1009 Triple Inversions (35分)(树状数组)
    Codeforces 1283F DIY Garland
    Codeforces Round #438 A. Bark to Unlock
    Codeforces Round #437 E. Buy Low Sell High
    Codeforces Round #437 C. Ordering Pizza
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/1937008.html
Copyright © 2011-2022 走看看