前言
函数
- 函数可以作为带有属性和方法的值当然还有参数进行传递
- Javascript中的作用域都是用函数来标明的,并不像C++中用 ” { } “ 来提供局部作用域,可以稍微参见一下闭包
创建函数的方式主要有两种:
- 函数表达式
var Foo = function () {};
- 函数声明
function Foo() {}
API 模式
- 回调模式:将函数作为参数传递,类似于C++里面的函数指针,但在Javascript里面会更容易实现
- 配置对象:控制函数参数数量,通过传递一个对象,将配置参数包含在此对象中,避免传递大量函数参数
- 返回函数:函数返回值为函数的函数
- Curry化:函数的部分求值
接下来详细介绍一下各模式:
-
回调模式的形式如下:
function httpRequest (url,callback) {
// ...
callback();
}经常可以利用此类模式去增加代码的复用性,便于扩展。
虽然在许多情况下这种方法简单而且可行,但是存在一些场合。比如回调函数不是匿名函数或全局函数,而是对象的方法。如果回调方法里面使用this来引用他所属的对象,这将导致不同的行为发生。例如:
//假设回调函数是myapp.paint()
var myapp = {
color: 'green'
};
myapp.paint = function(node) {
node.style.color = this.color;
};
var findNodes = function(callback) {
//寻找DOM中的一个节点找到后存入found中
// ...
if (typeof callback === 'function') {
callback(found);
}
// ...
};
/*
如果调用findNodes(myapp.paint),他并不会按照预期那样运行。因为this.color中的this并不是指向myapp而是全局对象:比如window
*/
/*
解决方法
*/
var findNodes = function(callback, callback_obj) {
// ...
if (typeof callback === 'function') {
callback.call(callback_obj, found);
}
// ...
} - 配置对象模式形式如下:
var person = {};
function addPerson(person, conf) {
person.name = conf.name || 'default name';
person.age = conf.age || 'default age';
person.sex = conf.sex || 'default sex';
person.id = conf.id || 'default id';
}
addPerson(person, {
name: 'James',
id: '0001',
});
// person: Object {name: "James", age: "default age", sex: "default sex", id: "0001"}此类模式的好处就是在设置参数的时候不用记住很多的参数和顺序,可以忽略可选参数。但是就是得记住参数的名称
-
返回函数:
// 函数初始化,然后接着继续执行...
var setup = function() {
var counter = 0;
return function() {
return ++counter;
}
}
var plus = setup();
plus(); // 1
plus(); // 2
plus(); // 3
// .... -
Curry化(也就是函数部分求值,如下):
// F(x,y) = x + y;
// F(0,y) = y;
// G(x) = F(0,y);
// G(1) = 1;
//
// 部分求值可以解释如下:
// 当函数的输入参数不全时,他会返回另一个函数来接收剩余的参数。
function currylize(fn) {
var slice = Array.prototype.slice,
stored_args = slice.call(arguments, 1);
return function() {
var new_args = slice.call(arguments),
args = stored_args.concat(new_args);
return fn.apply(null, args);
}
}
function add(x, y) {
return x + y;
}
var newAdd = currylize(add, 1);
newAdd(2); // 3Curry化的使用场合:当发现正在调用同一个函数,并且传递的参数绝大多数是相同的,那么这可能是个用于Curry化的不错选择