以函数抽象为单元
function parseAge(age) {
if (!_.isString(agr)) {
throw new Error('Expecting is String');
}
console.log('告警:接收到参数,准备类型转化');
var temp = parseInt(age, 10);
if (_.isNaN(temp)) {
console.log(['不能格式转化为数字', age].join(''));
}
return temp;
}
function fail(thing) {
throw new Error(thing);
}
function warn(thing) {
console.log(['告警:', thing].join(''));
}
function note(thing) {
console.log(['提示:', thing].join(''));
}
function parseAge(age) {
if (!_.isString(agr)) {
fail('Expecting is String');
}
note('接收到参数,准备类型转化');
var temp = parseInt(age, 10);
if (_.isNaN(temp)) {
warn(['不能格式转化为数字', age].join(''));
}
return temp;
}
以函数行为为单位
function naiveNth(data, index) {
if (!_.isNumber(index)) {
fail('参数不是一个数字');
}
if (!(_.isArray(data) || _.isString(data))) {
fail('data, 不支持下标取值');
}
if (index < 0 || index > data.length) {
fail('下标溢出');
}
return data[index];
}
function isIndex (data){
return _.isArray(data) || _.isString(data);
}
function naiveNth(data, index) {
if (!_.isNumber(index)) {
fail('参数不是一个数字');
}
if (!isIndex(data)) {
fail('data, 不支持下标取值');
}
if (index < 0 || index > data.length) {
fail('下标溢出');
}
return data[index];
}
// 常规实现
[2, 3, -1, -6, 0, -108, 42, 10].sort(function compareLessThanOrEqual(x, y) {
if (x < y) return -1;
if (y < x) return 1;
return 0;
});
// 函数编程进阶一
function compareLessThanOrEqual(x, y) {
if (x < y) return -1;
if (y < x) return 1;
return 0;
}
[2, 3, -1, -6, 0, -108, 42, 10].sort(compareLessThanOrEqual);
// 函数编程进阶二
function lessOrEqual(x, y) {
return x <= y;
}
// 一个比较器的高阶函数
function comparator(pred) {
return function(x, y) {
if (pred(x, y))
return -1;
else if (pred(y, x))
return 1;
else
return 0;
};
};
[2, 3, -1, -6, 0, -108, 42, 10].sort(comparator(lessOrEqual))
通过描述详细行为的编程方式
案例:
// 开始数字 99
// 重复以下内容到数字为1
// ---- 有x瓶啤酒
// ---- 拿走一个
// ---- 还有X - 1 个
// 最后的数字减1,下一个回合
// X为1的时候,输出没有啤酒
// 命令式编程风格
var lyrics = [];
for (var bottles = 99; bottles > 0; bottles--) {
lyrics.push(bottles + " bottles of beer on the wall");
lyrics.push(bottles + " bottles of beer");
lyrics.push("Take one down, pass it around");
if (bottles > 1) {
lyrics.push((bottles - 1) + " bottles of beer on the wall.");
} else {
lyrics.push("No more bottles of beer on the wall!");
}
}
function lyricSegment(n) {
return _.chain([])
.push(n + " bottles of beer on the wall")
.push(n + " bottles of beer")
.push("Take one down, pass it around")
.tap(function(lyrics) {
if (n > 1)
lyrics.push((n - 1) + " bottles of beer on the wall.");
else
lyrics.push("No more bottles of beer on the wall!");
})
.value();
}
function song(start, end, lyricGen) {
return _.reduce(_.range(start, end, -1), function(acc, n) {
return acc.concat(lyricGen(n));
}, []);
}
song(99, 0, lyricSegment)
// 实现一个复制函数,参数为一个数字和一个值,将值多次复制,放入一个数组之中
function repeat(times, VALUE) {
return _.map(_.range(times), function() { return VALUE; });
}
// 缺点 变量Value写死,不易拓展
function repeatedly(times, fun) {
return _.map(_.range(times), fun);
}
// eg:
repeatedly(3, function() {
return Math.floor((Math.random()*10)+1);
});
//=> [1, 3, 8]
repeatedly(3, function(n) {
document.getElementById('id' + n);
});
// 确定 复制次数是提前知道的
function iterateUntil(fun, check, init) {
var ret = [];
var result = fun(init);
while (check(result)) {
ret.push(result);
result = fun(result);
}
return ret;
};
// 优点:终止条件由函数决定
// 找到 1024 内所有 2的幂次方数
iterateUntil(
function() { return n + n },
function() { return n <= 1024; },
1
)
repeatedly(10, function(exp) { Math.pow(2, exp + 1) })
function invoker(NAME, METHOD) {
return function(target /* args ... */ ) {
if (!existy(target)) fail("Must provide a target");
var targetMethod = target[NAME];
var args = _.rest(arguments);
return doWhen((existy(targetMethod) && METHOD === targetMethod), function() {
return targetMethod.apply(target, args);
});
};
};
// 接收一个函数,返回只接受一个参数的函数
function curry(fun) {
return function(arg) {
return fun(arg);
};
}
// 看起来很多余,主要是是想解决js函数多余的参数
// eg:
['11', '11', '11', '11'].map(parseInt);
['11', '11', '11', '11'].map(curry(parseInt);
function curry2(fun) {
return function(secondArg) {
return function(firstArg) {
return fun(firstArg, secondArg);
};
};
}
var parseBinaryString = curry2(parseInt)(2);
parseBinaryString("111");
更好用的部分柯里化
function partial1(fun, arg1) {
return function( /* args */ ) {
var args = construct(arg1, arguments);
return fun.apply(fun, args);
};
}
function partial2(fun, arg1, arg2) {
return function( /* args */ ) {
var args = cat([arg1, arg2], arguments);
return fun.apply(fun, args);
};
}
// eg
if (!Function.prototype.bind)(function() {
var slice = Array.prototype.slice;
Function.prototype.bind = function() {
var thatFunc = this,
thatArg = arguments[0];
var args = slice.call(arguments, 1);
return function() {
var funcArgs = args.concat(slice.call(arguments))
return thatFunc.apply(thatArg, funcArgs);
};
};
})();
Lodash
Underscore
gitHub