1. 每个函数都是对象,因此函数上可以定义自己的属性。例如:
test.counter = 0;
function test() {
console.log(test.counter);
test.counter++;
}
test(); // 0
test(); // 1
test(); // 2
这样counter的值在多次调用函数test的时候能够保存下来,又避免了定义不必要的全局变量。
函数还可以把自己当作成一个数组对象,从而往自己身上存取多个数据。例如:
function fibonacci(n) {
if(fibonacci[n - 2] === undefined) {
fibonacci[n - 2] = fibonacci(n - 2);
}
if(fibonacci[n - 1] === undefined) {
fibonacci[n - 1] = fibonacci(n - 1);
}
return fibonacci[n - 1] + fibonacci[n - 2];
}
fibonacci[0] = 0;
fibonacci[1] = 1;
console.log(fibonacci(10)); // 55
console.log(fibonacci(50)); // 12586269025
如果直接递归求fibonacci数列,由于有很多重复的计算将导致计算效率极低。为了避免重复计算,一个办法是把已经计算得到的中间结果缓存起来。在上述代码中,中间结果缓存在函数自身的数组中。
2. 如果往构造函数上添加属性,还能实现类似于C++/Java上的静态变量和静态函数。例如如下例子:
function Account(name) {
this.name = name;
this.id = Account.nextId++;
}
Account.nextId = 100;
Account.prototype.toString = function() {
return "Name is: " + this.name + "; id is: " + this.id + ".";
}
var accountA = new Account("Harry");
var accountB = new Account("Peter");
console.log(accountA.toString()); // Name is: Harry; id is: 100.
console.log(accountB.toString()); // Name is: Peter; id is: 101.
在上述代码中,我们通过构造函数Account创建对象。我们希望每个对象的id属性都不一样。这个id属性通过Account.nextId生成。此时,Account.nextId就相当于是类型Account的一个静态变量。
在看一个往构造函数添加变量和函数的例子:
function Complex(real, imaginary) {
this.r = real;
this.i = imaginary;
}
Complex.prototype.add = function(that) {
return new Complex(this.r + that.r, this.i + that.i);
};
Complex.prototype.toString = function() {
return "{" + this.r + ", " + this.i + "}";
};
Complex.parse = function(s) {
try {
var m = Complex._format.exec(s);
return new Complex(parseFloat(m[1]), parseFloat(m[2]));
}
catch (x) {
throw new TypeError("Can't parse \"" + s + "\" as a complex number.");
}
};
Complex._format = /^\{([^,]+),([^}]+)\}$/;
var complex1 = Complex.parse("{1, 2}");
var complex2 = Complex.parse("{5, 3}");
var result = complex1.add(complex2);
console.log(result.toString()); // {6, 5}
在上面的代码中,Complex._format相当于类型Complex的静态变量,而Complex.parse相当于类型Complex的静态函数。