锁定老帖子 主题:读Ext之三(原型扩展)
精华帖 (0) :: 良好帖 (3) :: 新手帖 (0) :: 隐藏帖 (0)
|
|
---|---|
作者 | 正文 |
发表时间:2010-09-30
最后修改:2010-11-12
续上篇, Ext.ns = Ext.namespace;
有了一个简写的namespace。整个匿名函数执行完了。接下来 Ext.ns("Ext.util", "Ext.lib", "Ext.data"); Ext.elCache = {};
分别为Ext添加了util,lib,data,elCache属性,默认都是空的对象。 Ext.apply(Function.prototype, { createInterceptor : function(){ // ... }, createCallback : function(){ // ... }, createDelegate : function(){ // ... }, defer : function(){ // ... } }); Ext.apply在第一篇已经讲到,这里用来扩展Function,为其增加了四个方法createInterceptor、createCallback、createDelegate、defer。
createInterceptor 方法 createInterceptor : function(fcn, scope){ var method = this; return !Ext.isFunction(fcn) ? this : function() { var me = this, args = arguments; fcn.target = me; fcn.method = method; return (fcn.apply(scope || me || window, args) !== false) ? method.apply(me || window, args) : null; }; }, Interceptor顾名思义,拦截器。它却不是Strust2中的拦截器,但还是有部分相似之处。这里是利用所传函数fcn拦截,如果fcn返回false,将被拦截,true才执行。 Function.prototype.test = function(){ alert(this); }; function fn(){return 'test';} fn.test();
给Function.prototype添加了一个test方法,定义函数fn,fn会自动继承test方法,fn.test()时弹出的this可以看到就是fn自身。
function oldFn(){ alert('test'); } function ret(){ return false; } var newFn = oldFn.createInterceptor(ret); newFn();
oldFn继承了createInterceptor方法,且调用了它,参数是ret。这时createInterceptor内部的method, fcn.method就是oldFn;me,fcn.target则为window对象。改成如下,me,fcn.target则为obj了。 function oldFn(){ alert('test'); } function ret(){ return false; } var obj = {name:'jack'}; obj.method = oldFn.createInterceptor(ret); obj.method();
再往下看 function sayName(name){ alert('hello, ' + name); } function rule(name){ return name == 'snandy'; } var sayName2 = sayName.createInterceptor(rule); sayName2('zhangsan'); // -> no alert sayName2('snandy'); // -> "hello, snandy"
createCallback 方法 createCallback : function(/*args...*/){ // make args available, in function below var args = arguments, method = this; return function() { return method.apply(window, args); }; },
这个方法非常有用,实现简单。返回一个新函数,新函数内执行method(method是谁就不用再提了吧),会把外面的参数给传进来。 在给这些事件添加hanlder,又想传参或许也会用到 createCallback。 createDelegate : function(obj, args, appendArgs){ var method = this; return function() { var callArgs = args || arguments; if (appendArgs === true){ callArgs = Array.prototype.slice.call(arguments, 0); callArgs = callArgs.concat(args); }else if (Ext.isNumber(appendArgs)){ callArgs = Array.prototype.slice.call(arguments, 0); // copy arguments first var applyArgs = [appendArgs, 0].concat(args); // create method call params Array.prototype.splice.apply(callArgs, applyArgs); // splice them in } return method.apply(obj || window, callArgs); }; },
createDelegate 比 createCallback 更强大,除了能解决回调函数传参问题。还能控制: <a href="#" id="aa">SINA</a> <script type="text/javascript"> var aa = document.getElementById('aa'); function sayName(name){ alert('hello, ' + name); } var sayName2 = sayName.createDelegate(aa,['jack']); aa.onclick = sayName2; </script>
2,三个参数都传,appendArgs为true时,默认参数(DOM事件对象)位置不变(第一个),自定义参数args在最后 <a href="#" id="aa">SINA</a> <script type="text/javascript"> var aa = document.getElementById('aa'); function sayName(){ alert('实际参数长度:' + arguments.length); alert('hello, ' + arguments[0]); alert('hi, ' + arguments[1]); } var sayName2 = sayName.createDelegate(aa,['jack'],true); aa.onclick = sayName2; </script>
3, 三个参数都传,appendArgs为数字时将指定自定义参数的位置 <a href="#" id="aa">SINA</a> <script type="text/javascript"> var aa = document.getElementById('aa'); function sayName(name){ alert('实际参数长度:' + arguments.length); alert('hello, ' + arguments[0]); alert('hi, '+ arguments[1]); alert('hi, '+ arguments[2]); } var sayName2 = sayName.createDelegate(aa,['jack','lily'],0); aa.onclick = sayName2; </script>
此外,method的执行上下文应该增加this,这样实用一些了。 return method.apply(obj || this || window, callArgs);
接着看defer,指定函数在多少毫秒后执行 defer : function(millis, obj, args, appendArgs){ var fn = this.createDelegate(obj, args, appendArgs); if(millis > 0){ return setTimeout(fn, millis); } fn(); return 0; }
内部实用了刚刚提到的createDelegate方法,指定函数的执行上下文及参数设定。如果millis是正数则延迟执行返回setTimeout的返回值(一个数字),有必要可用clearTimeout终止。否则立即执行,返回0。
好了,以上是对Function.prototype的扩展。接下来是对String,Array的扩展。使用Ext.applyIf,第一篇 已提到Ext.applyIf不会覆盖已有的方法。 Ext.applyIf(String, { format : function(format){ var args = Ext.toArray(arguments, 1); return format.replace(/\{(\d+)\}/g, function(m, i){ return args[i]; }); } });
给String添加静态方法(类方法)format,可以把字符串中特殊写法({0},{1})用指定的变量替换。如 var href = 'http://www.sina.com.cn', text = '新浪'; var s = String.format('<a href="{0}">{1}</a>', href, text); alert(s); // --> <a href="http://www.sina.com.cn">新浪</a>
有点类似于JSP的EL表达式。
对Array扩展, Ext.applyIf(Array.prototype, { indexOf : function(o, from){ var len = this.length; from = from || 0; from += (from < 0) ? len : 0; for (; from < len; ++from){ if(this[from] === o){ return from; } } return -1; }, remove : function(o){ var index = this.indexOf(o); if(index != -1){ this.splice(index, 1); } return this; } });
indexOf 再熟悉不过了吧,String早有了。用来查找元素是否在数组中,如果有则返回该元素在数组中的索引,否则返回-1。该方法在 ECMAScript 5
中已经引入,各浏览器的新版本都实现了。
好了,以上3篇是整个Ext-core的Ext.js。
声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
发表时间:2010-10-09
写的不错,楼主研读源码的精神值得学习。
|
|
返回顶楼 | |
发表时间:2010-10-09
createDelegate是居家旅行必备良药
|
|
返回顶楼 | |
发表时间:2010-10-12
确实,Ext除了文档中提到的组件,还有很多很实在的工具藏在源代码里面。
我就特别喜欢用Ext对于时间处理的扩展方法。 |
|
返回顶楼 | |
浏览 3230 次