【读书笔记】读《JavaScript模式》 - JavaScript函数常用模式
API模式:回调模式、配置对象、返回函数;
初始化模式:即时函数、即时对象初始化、初始化分支;
性能模式:备忘模式、自定义模式
1 //*********************** API模式 *********************** 2 /** 3 * ---------------------- 回调模式 ---------------------- 4 * 5 * 1>要写出通用和可复用的代码,回调模式可以帮助实现这种通用化。 6 * 2>不需要预测和实现能想到的每一项功能,因为这样会迅速使我们的代码膨胀, 7 * 而绝大多数用户永远不会需要其中大量的功能。相反,可以专注于核心功能并提供“挂钩”形式的回调函数, 8 * 这会使我们很容易构建、扩展,以及自定义我们的方法。 9 */ 10 //方式一 11 var findNodes = function () { 12 var i = 10000, 13 nodes = [], 14 found; 15 while (i) { 16 i -= 1; 17 //这里是复杂的业务逻辑 18 nodes.push(found); 19 } 20 return nodes; 21 } 22 23 var hide = function (nodes) { 24 for (var i = 0, len = nodes.length; i < len; i += 1) { 25 nodes[i].style.display = 'none'; 26 } 27 } 28 29 hide(findNodes()); 30 31 //方式二 32 var findNodes = function (callback) { 33 var i = 10000, 34 nodes = [], 35 found; 36 while (i) { 37 i -= 1; 38 //这里是复杂的业务逻辑 39 if (typeof callback === 'function') { 40 callback(found); 41 } 42 nodes.push(found); 43 } 44 return nodes; 45 } 46 47 var hide = function (node) { 48 node.style.display = 'none'; 49 } 50 51 findNodes(hide); 52 53 //简洁点,将回调函数直接写在findNodes函数中 54 findNodes(function (node) { 55 node.style.display = 'block'; 56 }) 57 58 /** 59 * ---------------------- 配置对象模式 ---------------------- 60 * 61 * 封装传递参数为一个对象,灵活了函数的调用方式,何乐而不为 62 */ 63 function addPerson(name, gender, age, address) { 64 //... 65 } 66 67 //将参数封装 68 var conf = { 69 name: 'king', 70 gender: 'male', 71 age: 25, 72 address: 'xxxxxx' 73 } 74 addPerson(conf); 75 76 //简写之 77 addPerson({ 78 name: 'king', 79 gender: 'male', 80 age: 25, 81 address: 'xxxxxx' 82 }) 83 84 /** 85 * ---------------------- 返回函数模式 ---------------------- 86 * 87 * 函数里面返回函数,它创建了一个闭包,可以使用这个闭包存储一些私有数据, 88 * 而这些数据仅可被该返回函数访问,但外部代码却无法访问。 89 */ 90 var setup = function () { 91 var count = 0; 92 return function () { 93 return count++; 94 } 95 } 96 var next = setup(); 97 next(); //1 98 next(); //2 99 next(); //3
//*********************** 初始化模式 *********************** /** * ---------------------- 即时函数模式 ---------------------- */ //文件module1.js中定义的模块module1 (function () { //模块1的所有代码 })(); //文件module2.js中定义的模块module2 (function () { //模块2的所有代码 })(); /** * ---------------------- 即时对象初始化模式 ---------------------- * * 这种模式的优点与即时函数模式的优点是相同的:可以在执行一次性的初始化任务时保护全局命名空间。、 * 与仅仅将一堆代码包装到匿名函数的方法相比。这种模式看起来设计更多的语法特征, * 但是如果初始化任何更加复杂(它们也往往的确比较复杂),它会使整个初始化过程显得更有结构化。 * 其语法结构如下: * ({...}).init(); * ({...}.init()); */ ({ name: 'king', password: '123', say: function () { return 'I am ' + this.name + ', and my password is ' + this.password; }, init: function () { console.log(this.say()); } /** * 这种模式主要适用于一次性的任务,而且在init()完毕后也没有保存对该对象的访问。 * 如果想在init()完毕后保存对该对象的一个引用,可以通过在init()尾部添加"return this;"语句实现该功能。 */ }).init(); //I am king, and my password is 123 /** * ---------------------- 初始化时分支模式 ---------------------- */ //每次调用utils.addListener()或utils.removeListener()时,都会重复地进行相同检查 var utils = { addListener: function (elem, type, fn) { if (typeof window.addEventListener === 'function') { elem.addEventListener(type, fn, false); } else if (typeof window.attachEvent === 'function') { //IE elem.attachEvent('on' + type, fn); } else { elem['on' + type] = fn; } }, removeListener: function () { if (typeof window.removeEventListener === 'function') { elem.removeEventListener(type, fn, false); } else if (typeof window.detachEvent === 'function') { //IE elem.detachEvent('on' + type, fn); } else { elem['on' + type] = null; } } } //采用分支 var utils = { addListener: null, removeListener: null } //分开嗅探浏览器特征,然后使用加载时分支仅执行一次嗅探 if (typeof window.addEventListener === 'function') { utils.addListener = function (elem, type, fn) { elem.addEventListener(type, fn, false); }; utils.removeListener = function (elem, type, fn) { elem.removeListener(type, fn, false); }; } else if (typeof window.detachEvent === 'function') { //IE utils.addListener = function (elem, type, fn) { elem.attachEvent('on' + type, fn); }; utils.removeListener = function (elem, type, fn) { elem.detachEvent('on' + type, fn); }; } else { utils.addListener = function (elem, type, fn) { elem['on' + type] = fn; }; utils.removeListener = function (elem, type, fn) { elem['on' + type] = null; }; }
//*********************** 性能模式 *********************** /** * ---------------------- 备忘模式 ---------------------- * * 使用函数属性以便使得计算过的值无须再次计算 */ var myfunc = function (param) { if (!myfunc.cache[param]) { var result = {}; //...开销很大的操作... myfunc.cache[param] = result; } return myfunc.cache[param]; } //缓存存储 myfunc.cache = {}; /** * ---------------------- 自定义函数模式 ---------------------- * * 当函数有一些初始化准备工作要做,并且仅需要执行一次,那么这个模式就非常有用。 * 因为并没有任何理由去执行本可以避免的重复工作,即该函数的一些部门可能并不再需要。 * 在这种情况下,自定义函数可以更新自身的实现。使用此模式可以显著地帮助提升应用程序的性能, * 这是由于重新定义的函数仅执行了更少的工作。 */ var scareMe = function () { alert('Boo!'); scareMe = function () { alert('Double boo!'); }; } scareMe(); //Boo! scareMe(); //Double boo! scareMe(); //Double boo!