闭包:
闭包的功能
1、保存函数执行状态
将字符串中的一些特定字符按顺序用数组中的元素替换,例如:
* var arr = ['c','f','h','o'];
* var str = 'ab4de8g4ijklmn7';
* 替换后 str == 'abcdefghijklmno';
* replace的用法请参考https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/String/replace
**/
// var arr = ['c','f','h','o'];
// var str = 'ab4de8g4ijklmn1';
// console.log(str);
// var func = (function(){
// // count变量会保存在闭包作用域内,表示func被调用次数(即正在替换第几个字符)
// var count = 0;
// return function(){
// return arr[count++];
// }
// })();
// str = str.replace(/\d/g, func)
// console.log(str);
2、封装
闭包使用举例2 -- 封装
1.暴露type类型和start, stop, getStatus方法
2.隐藏status,light对象状态
**/
var Car = function(type){
var status = "stop",
light = "off";
return {
type: type,
start: function(){
status = "driving";
light = "on";
},
stop: function(){
status = "stop";
light = "off";
},
getStatus: function(){
console.log(type + " is " + status + " with light " + light);
}
}
}
var audi = new Car("audi");
audi.start();
audi.getStatus();
audi.stop();
audi.getStatus();
3、性能优化
//不使用闭包
function sum(i, j) {
var add = function(i, j){
return i+j;
}
return add(i, j)
}
var startTime = new Date();
for(var i = 0; i< 1000000; i++) {
sum(1,1);
}
var endTime = new Date();
console.log(endTime - startTime);
// 使用闭包.不需要保存状态的函数使用闭包
var sum = (function() {
var add = function(i, j){
return i+j;
}
return function(i,j) {
add(i, j);
}
})()
var startTime = new Date();
for(var i = 0; i< 1000000; i++) {
sum(1,1);
}
var endTime = new Date();
console.log(endTime - startTime);
First-class function
函数可以当做普通变量使用
函数作为参数
异步回调函数
函数作为返回值
Function.prototype.bind function原型对象上的一个方法,所有函数都可以调用
用法同apply
区别:bind不会立即调用 。bind保存的函数的引用,可以接受参数。
move函数实现移动平面图上一个点位置功能
var move = function(x,y){
this.x += x;
this.y += y;
}
// // 定一个点p
var p = {x:1, y:1};
// bind方法收受一个参数,并返回一个接受余下参数的函数过程。此时p点并没有移动。
var pmove0 = move.bind(p);
console.log(p);
pmove0(1,2);
console.log(p);// 这时p移动到了(2,3)位置。
// 当然你也可以这样调用
var pmove1 = move.bind(p,1);//只传递一个参数
console.log(p);
pmove1(2);//这里再传一个参数
console.log(p);
或者这样调用
var pmove2 = move.bind(p,1,2);
console.log(p);
pmove2();
console.log(p);
函数的柯里化 curry
1. 函数柯里化通常是指把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的并且返回一个接受余下的参数而且返回结果的新函数的技术。*/
1、最简单的柯里化
sum函数接受三个参数,并返回求和结果
var sum = function(a,b,c) {
return a+b+c;
}
// 最简单柯里化的sum函数
var sum_curry = function(a){
return function(b,c){
return a+b+c;
}
}
- 更泛化的定义是指给函数分步传递参数,每次函数接受部分参数后应用这些参数,并返回一个函数接受剩下的参数,这中间可嵌套多层这样的接受部分参数的函数,直至返回最后结果。归纳一下就是逐步传参,逐步缩小函数的适用范围,逐步求解的过程。
// 2. 泛化的柯里化
// currying实现将一个函数转变为柯里化函数
var currying = function (fn) {
var _args = [];
return function () {
if (arguments.length === 0) {
// 实现最终的计算
return fn.apply(this, _args);
}
// 这里只是简单的将参数缓存起来(用于解释柯里化概念,并非实际应用场景)
Array.prototype.push.apply(_args, [].slice.call(arguments));
return arguments.callee;
}
};
// sum函数接受任意参数,并返回求和结果
var sum=function () {
var total = 0;
for (var i = 0, c; c = arguments[i++];) {
total += c;
}
return total;
};
// 或得一个泛化柯里化的sum函数
var sum_curry = currying(sum);
sum_curry(1)(2,3);
sum_curry(4);
console.log(sum_curry());
- 从更上层的角度去理解,柯里化允许和鼓励你将一个复杂过程分割成一个个更小的更容易分析的过程(这些小的逻辑单元将更容易被理解和测试),最后这样一个难于理解复杂的过程将变成一个个小的逻辑简单的过程的组合。