函数类型

在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(); //

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

既然这种函数对象也有自己的特色,我们将它与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 关键字,也可以没有,这样说来,这些变体是等价的。

js 函数-Tom的更多相关文章

  1. js函数的伪重载

    这也是今天写东西是遇到的一个问题,导致我联想起了函数重载的问题. 在javascript中是没有函数重载机制的,对于用惯了java开发的同学可能就表示吃惊了,我屮艸芔茻,函数 没有重载?那怎么搞?!! ...

  2. (day65、66)Vue基础、指令、实例成员、JS函数this补充、冒泡排序

    目录 一.Vue基础 (一)什么是Vue (二)为什么学习Vue (三)如何使用Vue 二.Vue指令 (一)文本指令 (二)事件指令v-on (三)属性指令v-bind (四)表单指令v-model ...

  3. 3.3 js函数

    1.函数语法: 函数声明的方式:function 函数名(参数1,参数2-){//函数体;}函数调用:函数名(参数1,参数2-); 函数内不一定都指定返回值. 如果需要指定返回值,可用 return ...

  4. Js函数function基础理解

    正文:我们知道,在js中,函数实际上是一个对象,每个函数都是Function类型的实例,并且都与其他引用类型一样具有属性和方法.因此,函数名实际上是指向函数对象的指针,不与某个函数绑定.在常见的两种定 ...

  5. js函数表达式和函数声明的区别

    我们已经知道,在任意代码片段外部添加包装函数,可以将内部的变量和函数定义"隐 藏"起来,外部作用域无法访问包装函数内部的任何内容. 例如: var a = 2; function ...

  6. 通用js函数集锦<来源于网络> 【二】

    通用js函数集锦<来源于网络> [二] 1.数组方法集2.cookie方法集3.url方法集4.正则表达式方法集5.字符串方法集6.加密方法集7.日期方法集8.浏览器检测方法集9.json ...

  7. 通用js函数集锦<来源于网络/自己> 【一】

    通用js函数集锦<来源于网络/自己>[一] 1.返回一个全地址2.cookie3.验证用户浏览器是否是微信浏览器4.验证用户浏览器是否是微博内置浏览器5.query string6.验证用 ...

  8. 100多个基础常用JS函数和语法集合大全

    网站特效离不开脚本,javascript是最常用的脚本语言,我们归纳一下常用的基础函数和语法: 1.输出语句:document.write(""); 2.JS中的注释为//3.传统 ...

  9. JS函数

    1.document.write(""); 输出语句2.JS中的注释为//3.传统的HTML文档顺序是:document->html->(head,body)4.一个浏 ...

随机推荐

  1. jq 动态判断设备添加对应meta viewport属性内同

    1.常见的单位 dip, dp, px, sp之间的区别: dip: device independent pixels(设备独立像素). 不同设备有不同的显示效果,这个和设备硬件有关,一般我们为了支 ...

  2. java 练习题

    题目:想控制台输1-3个整数,按顺序为年,月,日.#号键结束输入.若输入一个整数,则为年份,程序判断是闰年还是平年:若输入两个整数,则为年份和月份,程序将输出该年的月份的天数:若输入3个整数:则为年, ...

  3. P问题、NP问题和NPC问题

    P问题.NP问题和NPC问题 这或许是众多OIer最大的误区之一.    你会经常看到网上出现“这怎么做,这不是NP问题吗”.“这个只有搜了,这已经被证明是NP问题了”之类的话.你要知道,大多数人此时 ...

  4. SQL Server 索引和表体系结构(三)

    转自:http://www.cnblogs.com/chenmh/p/3785285.html 包含列索引 概述 包含列索引也是非聚集索引,索引结构跟聚集索引结构是一样,有一点不同的地方就是包含列索引 ...

  5. 三种常见设计模式 - Factory

    创建型模型 一.简单工厂模式 靠 if else 或者 select case 等分支去控制不同对象的创建,难以维护 二.工厂方法模式  Factory 实现方式:将创建对象的方法定义成一个接口,通过 ...

  6. UVa(1658),Admiral,海军上将,拆点,MCMF

    题目链接:https://uva.onlinejudge.org/external/16/1658.pdf 题意:求1到N的两条路(不能相交),距离和最小. 分析: 第一次做拆点,有点意思.刚开始一直 ...

  7. python代码

    f=open('/home/xbwang/newtextsimilarity/data/glove/glove.840B.300d.txt','r') count = 0 print ' '.join ...

  8. LAMMP架构的企业级应用

    LAMMP架构的企业级应用 ========================================= LAMMP是什么 LAMMP的实现 LAMMP适用的生产环境 ============= ...

  9. 【leetcode❤python】 234. Palindrome Linked List

    #-*- coding: UTF-8 -*-class Solution(object):    def isPalindrome(self, head):        ""&q ...

  10. Windows Live Writer代码高亮插件对比

    一.Paste ASVisual Studio Code 参考:http://www.cnblogs.com/mikelij/archive/2010/11/13/1876199.html 插件下载: ...