日期:2014-05-16 浏览次数:20320 次
本文通过解决一个问题,引出javascript的概况
?
问题:? 有两种不同的视图,界面上有个按钮供点击来实现视图间的切换
最直观也简单的想法:
var cur = 1; function view1(){} function view2(){} function control(){ window['view' + cur](); cur = cur > 1 ? 1 : 2; } control(); control(); control(); control();
思考一下,有个全局变量总是不爽, 设想某个函数
function evilF(){ cur = 0; }
那么我们的control函数就成了受害者了.? 所以要想法把cur藏起来,试试面向对象如何?因为封装是其特色之一。??
function F(start){ this.cur = start; } F.prototype.control = function(){ window['view' + this.cur](); this.cur = this.cur > 1 ? 1 : 2; }; var controller = new F(1); controller.cur = 3; //Oops controller.control();
顺便做了一个小改进, 用户可以指定从那个页面开始了。结果报错了,问题是我们还能改cur的值。 难道就无计可施了吗? 该闭包闪亮登场了!(It's show time for closure!)
function F(start){ var obj = {}; obj.control = function(){ window['view' + start](); start = start > 1 ? 1 : 2; }; function P(){} P.prototype = obj; return new P(); } var controller = new F(1); controller.start = 3; controller.control(); controller.control(); controller.control = function(){console.log('blahblah');}; controller.control(); delete controller.control; // allow control to shine through from prototype. controller.control();
万事大吉,除非用户把control给覆盖掉了,这样原型里面的就找不到了,当删掉自定义的之后,一切恢复如初。
换个角度来思考, 这个问题跟什么比较类似呢?日历!
日历的提示,无非是从周一到周日循环复始而已,我们想要的正是类似的功能。我们也可以写一个生成器函数,把这种思想推而广之。
function func_generator(funcs, start){?????????????????????????? ? ?? start = start || 0; ?? funcs = funcs || []; ?? var len = funcs.length; ?? return function () { ??????? if(!len){ ?????????? return undefined; ??????? } ??????? if(start >= len){ ?????????? start %= len; ??????? } ??????? return funcs[start++] ; ?? }; } var view_toggler = func_generator([function (){console.log('view1');}, function(){console.log('view2');}], 1); view_toggler().apply(null,[]); view_toggler().apply(null,[]); view_toggler().apply(null,[]); view_toggler().apply(null,[]);
事情好起来了,除非用户把func_generator 给重写了, 为防止别人无心破环我们的成果, 再多做出一点努力把,把名字放长一点,打个包
var toolkit = (function(){ return { func_generator: function(funcs, start){ start = start || 0; start = start < 0 ? 0 : start; ?funcs = funcs || []; var len = funcs.length; return function () { if(!len){ return undefined; } if(start >= len){ start %= len; } return funcs[start++] ; }; } }; })(); var view_toggler = toolkit.func_generator([function (){console.log('view1');}, function(){console.log('view2');}], 0); view_toggler().apply(null,[]); view_toggler().apply(null,[]); view_toggler().apply(null,[]); view_toggler().apply(null,[]);
现在用户把我们的toolkit搞砸的概率大大减小了。
?
再多做一点, 让用户可以自由指定从那里开始切换
var toolkit = (function(){ return { func_generator: function(funcs, start){ start = start || 0; start = start < 0 ? 0 : start; funcs = funcs || []; var len = funcs.length; return function () { if(!len){ return undefined; } if(arguments.length){ start = arguments[0]; } if(start >= len){ start %= len; } return funcs[start++] ; }; } }; })(); var view_toggler = toolkit.func_generator([function (){console.log('view1');}, function(){console.log('view2');}, function(){console.log('view3');}, function(){console.log('view4');}], 0); view_toggler().apply(null,[]); view_toggler().apply(null,[]); view_toggler().apply(null,[]); view_toggler(0).apply(null,[]); view_toggler().apply(null,[]);