• js 函数-Tom


    函数类型

    在ECMAScript 中有三种函数类型:函数声明,函数表达式和函数构造器创建的函数。每一种都有自己的特点。

    函数声明

    函数声明(缩写为FD)是这样一种函数:
    1. 有一个特定的名称
    2. 在源码中的位置:要么处于程序级(Program level),要么处于其它函数的主体(FunctionBody)中
    3. 在进入上下文阶段创建
    4. 影响变量对象
    5. 以下面的方式声明
    function exampleFunc() {
    ...
    }

    这种函数类型的主要特点在于它们仅仅影响变量对象(即存储在上下文的VO中的变量对象)。该特点也解释了第二个重要点(它是变量对象特性的结果)——在代码执行阶段它们已经可用(因为FD在进入上下文阶段已经存在于VO中——代码执行之前)。

    例如(函数在其声明之前被调用)

    foo();

    function foo() {
    alert('foo');
    }

    另外一个重点知识点是上述定义中的第二点——函数声明在源码中的位置:

    // 函数可以在如下地方声明:
    // 1) 直接在全局上下文中
    function globalFD() {
    // 2) 或者在一个函数的函数体内
    function innerFD() {}
    }

    只有这2个位置可以声明函数,也就是说:不可能在表达式位置或一个代码块中定义它。

    另外一种可以取代函数声明的方式是函数表达式,解释如下:

    函数表达式

    函数表达式(缩写为FE)是这样一种函数:
    1. 在源码中须出现在表达式的位置
    2. 有可选的名称
    3. 不会影响变量对象
    4. 在代码执行阶段创建

    这种函数类型的主要特点在于它在源码中总是处在表达式的位置。最简单的一个例子就是一个赋值声明:

    var foo = function () {
    ...
    };

    该例演示是让一个匿名函数表达式赋值给变量foo,然后该函数可以用foo这个名称进行访问——foo()。

    同时和定义里描述的一样,函数表达式也可以拥有可选的名称:

    var foo = function _foo() {
    ...
    };

    需要注意的是,在外部FE通过变量“foo”来访问——foo(),而在函数内部(如递归调用),有可能使用名称“_foo”。

    如果FE有一个名称,就很难与FD区分。但是,如果你明白定义,区分起来就简单明了:FE总是处在表达式的位置。在下面的例子中我们可以看到各种ECMAScript 表达式:

    // 圆括号(分组操作符)内只能是表达式
    (function foo() {});

    // 在数组初始化器内只能是表达式
    [function bar() {}];

    // 逗号也只能操作表达式
    1, function baz() {};

    表达式定义里说明:FE只能在代码执行阶段创建而且不存在于变量对象中,让我们来看一个示例行为:

    // FE在定义阶段之前不可用(因为它是在代码执行阶段创建)

    alert(foo); // "foo" 未定义

    (function foo() {});

    // 定义阶段之后也不可用,因为他不在变量对象VO中

    alert(foo); // "foo" 未定义

    相当一部分问题出现了,我们为什么需要函数表达式?答案很明显——在表达式中使用它们,”不会污染”变量对象。最简单的例子是将一个函数作为参数传递给其它函数。

    function foo(callback) {
    callback();
    }

    foo(function bar() {
    alert('foo.bar');
    });

    foo(function baz() {
    alert('foo.baz');
    });

    在上述例子里,FE赋值给了一个变量(也就是参数),函数将该表达式保存在内存中,并通过变量名来访问(因为变量影响变量对象),如下:

    var foo = function () {
    alert('foo');
    };

    foo();

    另外一个例子是创建封装的闭包从外部上下文中隐藏辅助性数据(在下面的例子中我们使用FE,它在创建后立即调用):

    var foo = {};

    (function initialize() {

    var x = 10;

    foo.bar = function () {
    alert(x);
    };

    })();

    foo.bar(); // 10;

    alert(x); // "x" 未定义

    我们看到函数foo.bar(通过[[Scope]]属性)访问到函数initialize的内部变量“x”。同时,“x”在外部不能直接访问。在许多库中,这种策略常用来创建”私有”数据和隐藏辅助实体。在这种模式中,初始化的FE的名称通常被忽略:

    (function () {
    // 初始化作用域
    })();

    还有一个例子是:在代码执行阶段通过条件语句进行创建FE,不会污染变量对象VO。

    
    
    var foo = 10; 
    var bar = (foo % 2 == 0 ? function () { alert(0); } : function () { alert(1); });
    bar(); // 0
    
    

    通过函数构造器创建的函数

    既然这种函数对象也有自己的特色,我们将它与FD和FE区分开来。其主要特点在于这种函数的[[Scope]]属性仅包含全局对象:

    var x = 10;

    function foo() {

    var x = 20;
    var y = 30;

    var bar = new Function('alert(x); alert(y);');

    bar(); // 10, "y" 未定义

    }

    我们看到,函数bar的[[Scope]]属性不包含foo上下文的Ao——变量”y”不能访问,变量”x”从全局对象中取得。顺便提醒一句,Function构造器既可使用new 关键字,也可以没有,这样说来,这些变体是等价的。

  • 相关阅读:
    sql 拼写
    五、URL Routing介绍
    六、防止JavaScript注入攻击
    七、创建自定义的HTML Helper
    二、理解Models,Views,Controllers
    一、使用ASP.NET MVC创建应用程序
    自己写的临时表应用
    四、理解视图层,视图数据和HTML辅助
    三、理解控制器、控制器动作和ActionResults
    Extensions (扩展)方法
  • 原文地址:https://www.cnblogs.com/weilantiankong/p/4533816.html
Copyright © 2020-2023  润新知