[JS] JavaScript进阶教程:奇淫巧计
JavaScript进阶教程:奇淫巧计迭代器
此处可能说成枚举器更好,因为是叫Enumerator而不是Iterator。在JavaScript中实现了一个简单的迭代模式的类:Enumerator。
为什么要用这个呢?一般来说使用迭代器目的是为了顺序访问另外一个类中的元素而不必暴露类的内部表示。关于迭代模式,更详细的请参阅Gof的《Design Pattern》
该类有五个方法:
function Enumerator(Collection); //构造函数 function atEnd(); //是否到头了 function item(); //返回当前元素 void function moveFirst();//将当前元素指向第一个元素 void function moveNext();//将当前元素指向下一个元素 |
其中构造函数指定一个集合就可以了,例如数组,或其他实现了IEnumVariant接口的自动化对象(例如Scripting.FileScriptingObject中的IFileCollection接口)
使用方法:
var arr=new Array(1,2,3,4,5,6,7,8,9,10); for(var enu=new Enumerator(arr);!enu.atEnd();enu.moveNext()) { alert(enu.item()); } |
是不是觉得有些复杂?呵呵,很多模式很多东西都是这样,用在小的地方会显得臃肿没用,正所谓虎落平阳被犬欺,小地方不是他发挥能力的地方[。
函数对象
在JavaScript中,函数对象有多种表示方法,一个是静态定义,一个是动态定义,常见的静态定义和其他语言差不多:
function 函数名(参数列表) { 函数体 } |
而动态定义则特殊一点,在JavaScript中提供了函数对象来实现动态定义(说白了就是利用JavaScript的脚本特性来实现的“动态编译”):Function
Function对象的构造函数:
function Function(参数1,参数2,参数3....参数N,函数体);
创建一个函数如:
var add=new Function(“a”,”b”,”return a+b”);
调用这个函数:
alert(add(1,2));
这些参数和函数体都是字符串类型的。(P.S.至于这里的可变参数,后面要讲的)
Function对象的属性:
Function.arguments //静态属性,arguments是一个数组,用来存放当前调用该函数的参数,由于JavaScript里面Array也是一个Stack,可以简单点说这个arguments属性就是当前的调用参数栈,可变参数就是用这个实现的 Function.caller //静态属性,caller也是一个函数对象,表示调用当前函数的函数。利用这一点,可以很容易在调试大型JavaScript的时候实现栈贞展开操作以跟踪调用顺序 Function.constructor //成员属性,返回一个new操作符创建的对象实例的类型,也就是返回函数对象。例如 var obj=new MyObject();obj.constructor==MyObject Function.prototype //静态属性,返回某个实例/类的原型,通过prototype可以对这个类进行改造 |
arguments和prototype应用实例:
实现类似.net中System.String类的Format函数:
String.prototype.format=function(){ var tmp=this; var s; for(var i=0;i<arguments.length;i++) { s="{"+i+"}"; while(tmp.indexOf(s,0)!=-1) tmp=tmp.replace(s,arguments[i]); } return tmp; } var fmt=new String("ID:{0}\nName:{1}\nPrice:{2}"); alert(fmt.format(0,"Lex Chou","$100,000,000,000"));
|
caller应用举例:
利用caller实现栈贞展开跟踪调用顺序:
function StackFrameTrace(func) { var stackFrame=getName(func); for(var c=func;c=c.caller;stackFrame=getName(c)+"->"+stackFrame); return stackFrame; } function getName(obj) {//这个函数得到某个函数对象的名字 var m=String(obj).match(/function\s+([A-Za-z0-9_]+)/i); return m?m[1]:""; } |
比如说你在proc0里调用了proc1,proc1里调用了proc2,在proc2中拦截到异常,就可以通过StackFrameTrace