JavaScript 中使用 function 语句、使用 Function ()构造函数、定义函数直接量。无论是哪种定义函数,都是 Function 的实例,并将继承 Function 原型的方法。
在 JavaScript 中,使用 function 来声明函数。
function funName([args]) {
statements;
}
在函数体结构中,大括号是必不可少的,若是没有大括号,则会报错。
与其它结构不同, function 结构是静态的,不会直接执行,需要调用才能运行。因此,常把函数单独放在顶部或尾部,很少在分子结构或循环结构中定义函数。
var 语句和 function 语句都是变量声明语句,它们声明变量在 JavaScript 预编译时被解析。在预编译期, JavaScript 编译器会把代码中的 function 语句定义成一个函数变量,同时解析函数内部,把函数体内所有的参数、私有变量、嵌套函数作为属性注册到函数调用对象上,以便在执行期上调用函数能够快速执行。
使用 Function() 构造器可以快速生成函数:
var funName = new Function(p1 ,p2 ,... ,pn ,body );
构造器 Function 的参数都是字符串, p1 ~ pn 表示所创建函数的参数名称列表, body 表示所创建的函数的函数结构体语句,在 body 语句之间通过分号分隔。
Function() 构造器不是常用,因为一个函数体通常包含许多语句代码,如果讲这些代码以一行字符串的形式进行传递,代码的可读性会差。
使用 Function 构造器可以动态的创建函数,它不会把用户限制在 function() 语句预声明函数体中。使用 Function 构造器,能够将函数当作表达式使用,而不是当作一个结构,因此使用起来非常的灵活。其缺点就是, Function 构造函数是在执行期被编译,执行效率较低。
JavaScript 构造函数( constructor )也称构造器、类型函数,功能类似于对象模板,一个构造函数可生成任意多个实例,实例对象具有相同的属性、行为特征、但不相等。
function CallbackName(...arguments) {
this.property1 = arguments[0];
this.property2 = arguments[1];
// ...
this.method1 = function () {
//处理函数
};
// ...
//其它代码,可以包含 return 语句
}
建议构造函数的名称大写,好与普通的函数区分。
构造函数有以下两个明显的特点。
function Point(x, y) {
this.x = x;
this.y = y;
this.sum = function () {
return this.x + this.y;
};
}
调用构造函数
使用 new 命令可以调用构造函数,创建实例,并返回这个对象。
function Point(x, y) {
this.x = x;
this.y = y;
this.sum = function () {
return this.x + this.y;
};
}
var p1 = new Point(100, 200);
var p2 = new Point(300, 400);
console.log(p1.x);
console.log(p2.x);
console.log(p1.sum());
console.log(p2.sum());
如果不使用 new 命令,直接使用小括号调用构造函数,这时构造函数就是普通函数,不会生成实例对象, this 就代表调用函数的对象,在客户端指代全局对象 window 。
为避免错误,最有效的是在函数中其中严格模式。这样调用构造函数时,必须使用 new 命令,否则会抛出异常。
function Point(x, y) {
'use strict';
this.x = x;
this.y = y;
this.sum = function () {
return this.x + this.y;
};
}
或者使用 if 检测,如果 this 不是实例对象,则强迫返回实例对象。
function Point(x, y) {
if (!(this instanceof Point)) return new Point(x, y);
this.x = x;
this.y = y;
this.sum = function () {
return this.x + this.y;
};
}
构造函数返回值
构造函数允许使用 return 语句,如果返回值为简单值,这被忽略,直接返回 this 指代的实力对象;如果返回是对象,则覆盖 this 指代的实例,返回 return 后面跟随的对象。
function Point(x, y) {
this.x = x;
this.y = y;
return { x: true, y: false };
}
var p1 = new Point(100, 200);
console.log(p1.x); //返回 true
console.log(p1.y); //返回 false
引用构造函数
在普通函数内,使用 arguments.callee 可以引用函数自身。如果在严格模式下,是不允许使用 arguments.callee 引用函数,这时需要使用 new.target 来访问构造函数。
function Point(x, y) {
'use strict';
if (!(this instanceof new.target)) return new new.target(x, y);
this.x = x;
this.y = y;
}
var p1 = new Point(100, 200);
console.log(p1.x);
函数直接量就是结构固定的函数体。被称为匿名函数,也就是说函数没有函数名,仅包含 function 关键字、参数、函数体。
function([args]) {
statements
}
let 加以弥补,这个关键字允许你定义具有严格的块级作用域的一个变量。
const 声明创建了一个常量。
函数可以嵌套,因此定义复杂的嵌套结构函数。
嵌套函数只能在函数内部可见,函数外是不允许直接调用的。
使用 function 语句 | 使用 Function 构造函数 | 使用函数直接量 | |
---|---|---|---|
兼容 | 完全 | JavaScript1.1及以上 | JavaScript1.2以上 |
形式 | 语句 | 表达式 | 表达式 |
名称 | 有名 | 匿名 | 匿名 |
主体 | 标准语法 | 字符串 | 标准语法 |
性质 | 静态 | 动态 | 静态 |
解析 | 以命令的形式构造一个函数 | 解析函数体,能够动态创建一个新的函数对象 | 表达式形式构造一个函数对象 |
具有函数作用域 | 顶级函数。,具有顶级作用域 | 具有函数作用域 | 作用域 |
函数作用域
变量的作用范围(作用域)由声明它的位置决定,声明一个变量的同时也就指明了变量的作用范围。在一个确定的范围中,变量名应该是唯一的。
函数内部声明的变量只存在于函数内部。
我们把函数内部定义的变量称为"局部"变量,也就是属于函数这个"局部"的。函数之外声明的变量称为"全局"变量。全局变量和局部变量可以使用相同的名称,但仍然是不同的变量。
如果在函数中声明变量,则只有该函数中的代码可以访问或更改变量值,此时变量具有局部作用范围并被称为函数级变量。在函数中声明的变量具有局部范围,因此也被称为局部变量,每次执行函数时创建和消除此变量,并且无法从函数外部访问此变量。
如果在函数之外的代码声明构造块内声明变量,则该变量可以被脚本中所有函数所识别,称为 Script 级变量,具有脚本级作用范围。这些变量具有全局范围,因此也称为全局变量, HTML 网页中的任何 JavaScript 脚本代码都可以访问和修改此变量值。
变量存在的时间称为存活期。全局变量的存活期从被声明的那一刻起,直到程序运行结束。对于函数级变量,其存活期仅是该函数运行的时间,该函数结束后,变量随之消失。在执行函数时,局部变量是理想的临时存储空间,可以在不同函数中使用同名的局部变量,这是因为每个局部变量只被声明它的函数识别。
在 JavaScript 的程序执行时,系统会在内存中保留一块全局变量的区域。实际运用时,只需直接引用就可以将需要的变量取出。因为 JavaScript 类没有析构方法,因此应当慎用全局变量。
在函数中,如果不使用 var 关键字声明变量,而是直接为变量赋值,这样的变量具有全局作用范围,因为它实际上是在使用全局变量。
Function ()构造器创建的函数具有全局作用域,而 function ()和直接量定义的函数都有局部作用域。
var n = 1; // 全局变量
function f() {
var n = 2; // 局部变量
function e() {
return n;
}
return e; // 返回函数
}
alert(f()()); // 返回 2 ,调用函数 f 返回函数 e
var n = 1;
function f() {
var n = 2;
var e = new Function('return n;');
return e;
}
console.log(f() + ''); //
function anonymous() {
return n;
}
console.log(f()()); // 1 全局变量
解析方式
使用 function 语句和函数直接量定义的函数一般是先解析后执行,而使用 Function 构造器函数不是提前解析,在运行时动态解析和执行,所以,导致 Function 定义的函数在使用时效率微低于 function 。
var a = new Date();
var x = a.getTime();
for (var i = 0; i < 100000; i++) {
(function () {})();
}
var b = new Date();
var y = b.getTime();
console.log(y - x + ''); // 返回 10
/var a = new Date();
var x = a.getTime();
for (var i = 0; i < 100000; i++) {
new Function();
}
var b = new Date();
var y = b.getTime();
console.log(y - x + ''); // 返回 84
可用性
Function 和函数直接量定义的函数,有很大的灵活性,当函数仅用一次时,非常适合使用。但 Function 不如函数直接量。