JavaScript 设想形式与开辟实践念书笔记
近来应用碎片时刻在 Kindle 上面浏览《JavaScript 设想形式与开辟实践念书》这本书,刚开始浏览前两章内容,和人人分享下我以为能够在项目中用的上的一些笔记。
我的 github 项目会不定时更新,有须要的同砚能够移步到我的 github 中去检察源码:https://github.com/lichenbuliren/design-mode-notes
1、currying 函数柯里化
currying 又称部份求值。一个 currying 的函数首先会接收一些参数,接收了这些参数以后,该函数并不会马上求值,而是继承返回别的一个函数,将适才传入的参数在函数构成的闭包中被保存起来。待到函数被真正须要求值的时刻,之前传入的一切参数都会被一次性的用于求值。
假定我们须要编写一个盘算每月开支的函数,在天天完毕之前,我们要纪录天天花掉了多少钱。
通用 currying 函数:
var currying = function(fn) {
var args = [];
return function() {
if (arguments.length === 0) {
return fn.apply(this, args);
} else {
[].push.apply(args, arguments);
// 返回函数自身,这里指向 return 背面的匿名函数!
return arguments.callee;
}
}
};
var cost = (function() {
// 闭包存储末了的值
var money = 0;
return function() {
for (var i = 0, len = arguments.length; i < len; i++) {
money += arguments[i];
}
return money;
}
})();
// 转化成 currying 函数
// 这个时刻,闭包内部的 fn 指向真正的求值函数
// 也就是 cost 自运转的时刻返回的匿名函数
var cost = currying(cost);
cost(200);
cost(300);
cost(500);
// 求值输出
console.log(cost());
2、uncurrying 函数
Function.prototype.uncurrying = function() {
// 此时 selft 是背面例子中的 Array.prototype.push;
var self = this;
return function() {
// arguments: { '0': { '0': 1, length: 1 }, '1': 2 }
var obj = Array.prototype.shift.call(arguments);
return self.apply(obj, arguments);
}
};
// 别的一种完成体式格局
Function.prototype.uncurrying = function() {
var self = this;
return function() {
return Function.prototype.call.apply(self, arguments);
}
};
var push = Array.prototype.push.uncurrying();
var obj = {
"length": 1,
"0": 1
};
push(obj, 2);
console.log(obj);
3、函数撙节
JavaScript 中的函数大多数状况下都是由用户主动挪用触发的,除非是函数自身的完成不合理,不然我们平常不会碰到跟机能相干的题目。然则在一些少数状况下,函数的触发不是有由用户直接掌握的。在这些场景下,函数有能够被异常频仍的挪用,而造成大的机能题目。
函数被频仍挪用的场景:
window.onresize 事宜
mousemove 事宜
上传进度
函数撙节道理
上面三个提到的场景,能够发明它们面对的配合题目是函数被触发的频次太高。
比方我们在 window.onresize 事宜中要打印当前浏览器窗口大小,在我们拖拽转变窗口大小的时刻,掌握台1秒钟进行了 10 次。而我们实际上只须要 2 次或许 3 次。这就须要我们按时刻段来疏忽掉一些事宜要求,比方确保在 500ms 内打印一次。很明显,我们能够借助 setTimeout 来完成。
函数撙节完成
/**
* 函数撙节完成
* @param {Function} fn 须要撙节实行的函数
* @param {[type]} interval 事宜实行距离时刻,单元 ms
* @return {[type]} [description]
*/
var throttle = function(fn, interval) {
var _self = fn,
timer,
firstTime = true;
console.log(_self);
return function() {
var args = arguments,
_me = this; // 这里代表当前的匿名函数
console.log(_me);
if (firstTime) {
_self.apply(_me, args);
return firstTime = false;
}
if (timer) {
return false;
}
timer = setTimeout(function() {
clearTimeout(timer);
timer = null;
_self.apply(_me, args);
}, interval || 500);
};
};
window.onresize = throttle(function() {
console.log('test');
}, 500);
4、分时函数
我们经常会碰到这么一种状况,某些函数确实是用户主动挪用的,然则由于一些客观原因,这些函数会严重地影响页面机能。
一个例子就是建立 WebQQ 的 QQ 挚友列表。列表中一般会有成百上千个挚友,假如一个挚友用一个节点来示意,当我们在页面中衬着这个列表的时刻,能够要一次性往页面中建立成百上千个节点。
在短时刻内往页面中大批增加 DOM 节点明显也会让浏览器吃不消,我们看到的效果每每就是浏览器的卡顿以至假死。所以我们须要一个分时函数来处理这个题目
/**
* 分时函数例子
* 以建立 WebQQ 列表为例
* @param {[type]} data 函数实行须要用到的数据
* @param {Function} fn 真正须要分时实行的函数
* @param {[type]} count 每次建立一批节点的数目
* @param {[type]} interval 函数实行距离
* @return {[type]} [description]
*/
var timeChunk = function(data, fn, count, interval) {
var t;
var len = data.length;
var start = function() {
for (var i = 0; i < Math.min(count || 1, data.length); i++) {
var obj = data.shift();
fn(obj);
}
}
return function() {
t = setInterval(function() {
if (data.length === 0) {
return clearInterval(t);
}
start();
}, interval);
}
}
5、惰性加载函数
以建立事宜绑定函数为例:
在进入第一个前提分支以后,在函数内部重写这个函数,重写以后,就是我们所须要的函数,鄙人一次进入的时刻,就不再须要判断了。
/**
* 事宜绑定
* @param {[type]} el [description]
* @param {[type]} type [description]
* @param {[type]} handler [description]
*/
var addEvent = function(el, type, handler) {
if (window.addEventListener) {
addEvent = function(el, type, handler) {
el.addEventListener(type, handler, false);
}
} else if (window.attachEvent) {
addEvent = function(el, type, handler) {
el.attachEvent('on' + type, handler);
}
}
addEvent(el, type, handler);
}
Q&A
临时这么多,以后会不定期更新一些关于我读这本书的笔记内容!