- 浏览: 136186 次
- 性别:
- 来自: 长沙
文章分类
最新评论
-
古尔丹之颅:
呵呵,现在呢?
有点沉重 -
我自闲庭信步:
大哥为什么我用你的方法想打开word进行编辑的时候,程序只是将 ...
javascript word -
eye_java:
能给一两个具体点的场景吗?
soa -
流币的人:
public interface Callable<V& ...
Callable小知识 -
511543417:
Class.forName("com.mysql.j ...
java连接mysql数据库
Meta-Programming是一个比较广义的概念,你可以将它翻译成元类或者元模型编程,而它实际的意思,是用一系列方法生成类型模板。在 JavaScript,所谓的类型模板就是function,而元类,就是Function和由Function引出的一系列扩展。
关于JavaScript的Meta-Programming思想,其实有很多实现的例子和各种不同的方法,而在本文中,将它们归结为三个范式。所谓范式,你可以将它们理解为一些“公式化”的概念,或者某种模式,当你遇到同一类问题的时候,你应该寻找适合解决此类问题的“范式”。
第一范式:<new> T <=> <new> R:function(){donothing, return T.apply},R.prototype = T.prototype
这个范式被称为函数范式,它有如上面所列的标准形式和其他几种变形。标准形式被称为“前束”范式,因为它能够以语法等价的形式在函数T执行前插入一段代码。例如:
[复制]
Code:
Function.prototype.$verify = function(){ //对函数进行参数类型匹配
var me = this;
var _args = arguments;
var mins = function(){
for(var j= 0, len = _args.length; j< len; j++)
{
if(!$oneof(arguments[j],_args[j])){
throw new Error("函数的参数类型不匹配,位置:"+(j+1));
}
}
return me.apply(this, arguments);
}
mins.prototype = me.prototype;
return mins;
}
上面的代码对函数增加了参数类型匹配的扩展,它可以实现强制解释器对某个函数在调用之前进行参数类型匹配。例如:
[复制]
Code:
var foo = function(x,y){
alert(x+y);
}.$verify("number","number");
foo(1,2);
var foo2 = function(x,y){
x(y);
}.$verify(Function,"number");
//foo("error",2);
foo2(function(x){alert(x)},10);
//foo2("x","y");
var Class3 = function(x,y){
this.x = x;
this.y = y;
}.$verify("number","number");
Class3.prototype.dist2 = function(){return this.x*this.x + this.y*this.y};
var c = new Class3(10,20);
alert(c.dist2());
注意到上面这一段代码,$verify返回一个function,这个function是调用$verify的那个 function的一个第一范式迭代,这种处理方法在语法层面上达到很好的效果,而且它是无害的,这意味着你在编写和调试代码的时候可以得到$verify带来的好处,而在你发布代码的时候,你却可以很容易地用文本处理工具将$verify “尾巴”从你的代码中移出出去。
除此以外,第一范式的应用是很广泛的,因为它意味着你可以对函数进行任意扩展并且这些扩展不改变代码本身的语法结构!
你可以给函数增加某些不同功能的“尾巴”这些尾巴能够很好地帮你收集运行时信息、监视代码或者提供有用的调试信息。而这些所有的“尾巴”在你最终发布代码时,均可以非常方便地去掉,所以它们对实际运行的代码不会带来任何性能上的开销!这一点,对于开发者来说,无疑是非常非常好的消息!
第二范式:new T <=> T.apply(T.getPrototypeObject())
在几个月或者一年以前,我就在思考一个问题,我们知道,对于一个function T,脚本既可以把它当作一个方法来执行,又可以把它作为一个类型来构造,然而它们是不同的。除了new之外,其中语法上最显著的一个区别是T作为一个 function,既可以用()来直接操作,也可以享受call和apply带来的好处。而new,则受到比较大的限制,例如:
[复制]
Code:
function List()
{
this.members = Array.prototype.slice.apply(arguments); //Array支持可变参数,因为它可以作为函数来调用
}
function $list()
{
return new List(/*这里的参数应该怎么传?如果我希望$list(1,2,3...) <=> new List(1,2,3...)*/);
}
我们看到,相对function来讲,new操作受到较大的限制,当然上面这个实际问题是可以通过别的方式来解决的,但是用第二范式,无疑可以具有通用性地解决此类问题:
[复制]
Code:
G.objectAsPrototype = function(obj, c){
c = c || function(){};
c.prototype = obj;
return c;
};
Function.prototype.getPrototypeObject = function(){
var p = this.__templete__ || (this.__templete__= G.objectAsPrototype(this.prototype));
return new p();
};
Function.prototype.createInstance = function(){
var p = this.getPrototypeObject();
this.apply(p,arguments);
return p;
};
我们看到,第二范式解决了这样的问题,它告诉我们,JavaScript的new T操作等价于通过T的prototype创造一个“原型”对象,再用这个对象去执行T的构造函数,最终等价于产生了一个T的实例,但区别是后者不同于 new,是以一种函数调用的标准形式来产生的。
利用第二范式,我们可以很容易地增强JavaScript的原型继承,轻易地解决原型继承中关于构造函数延迟执行的需求(具体的将在另外一篇文章《深度探索高效率JavaScript继承》给出详细说明)
下面给出简单代码:
[复制]
Code:
Function.prototype.$pextends = function(p){
var me = this;
var ins = function()
{
this.$super = function(){
p.apply(this, arguments);
}
me.apply(this, arguments);
}
ins.prototype = p.getPrototypeObject();
return ins;
}
第三范式:new T <=> T.apply || new T(T.apply)
记得之前有人问过我一个有意思的问题,是关于js核心对象的扩展的。那个需求是实现一个自定义的Date类型MyDate,并且这个MyDate的所有构造参数都要和Date完全一致。之前,这个问题在解决的时候遇到一个困扰,具体的是这样的:
[复制]
Code:
function MyDate()
{
var ins = new Date(/*原生对象的扩展方式,可是如何处理可变参数呢?*/);
......
return ins;
}
而第三范式的意思是说,对于所有的核心对象,都满足如下两种情况之一:要么函数调用的返回结果等效于new操作,要么函数调用的返回结果利用new构造后等同于原始的new操作。Date的问题满足后者,也就是说,对于这个问题,将上面的代码改写成如下:
[复制]
Code:
function MyDate()
{
var ins = new Date(Date.apply(this, arguments));
......
return ins;
}
即可满足需求。
显然,这个第三范式并不是一个JavaScript类型默认遵循的范式,不过,有趣的是,几乎所有的核心对象都遵循第三范式:
Array、Function 满足范式右侧的第一个条件
Number、Boolean、String、Date、RegExp 满足范式右侧的第二个条件
所以,利用第三范式,我们可以实现核心对象的继承方法(关于核心对象继承的详细内容也会在《深度探索高效率JavaScript继承》给出详细讨论):
[复制]
Code:
Function.prototype.$cextends = function(p){
var me = this;
return function()
{
var ins = p.apply(this, arguments);
ins instanceof p || (ins = new p(ins));
me.apply(ins,arguments);
return ins;
}
}
除了继承核心对象之外,第三范式还有其他很有趣的应用:
[复制]
Code:
var MyFunction = function(){
this.m = function(){alert("static m")}
this.prototype.m = function(){alert("m")};
}.$cextends(Function);
//简单实现的Function Template
var X = new MyFunction("alert(1)");
var x = new X();
X.m();
x.m();
上面这段代码实现了一个自定义的函数模版,这样使用者就能够很方便地自己扩展Function,这个模式的意义是让Function元类具备有扩展能力,这种能力正是Meta-Programming所需要的。
关于JavaScript的Meta-Programming思想,其实有很多实现的例子和各种不同的方法,而在本文中,将它们归结为三个范式。所谓范式,你可以将它们理解为一些“公式化”的概念,或者某种模式,当你遇到同一类问题的时候,你应该寻找适合解决此类问题的“范式”。
第一范式:<new> T <=> <new> R:function(){donothing, return T.apply},R.prototype = T.prototype
这个范式被称为函数范式,它有如上面所列的标准形式和其他几种变形。标准形式被称为“前束”范式,因为它能够以语法等价的形式在函数T执行前插入一段代码。例如:
[复制]
Code:
Function.prototype.$verify = function(){ //对函数进行参数类型匹配
var me = this;
var _args = arguments;
var mins = function(){
for(var j= 0, len = _args.length; j< len; j++)
{
if(!$oneof(arguments[j],_args[j])){
throw new Error("函数的参数类型不匹配,位置:"+(j+1));
}
}
return me.apply(this, arguments);
}
mins.prototype = me.prototype;
return mins;
}
上面的代码对函数增加了参数类型匹配的扩展,它可以实现强制解释器对某个函数在调用之前进行参数类型匹配。例如:
[复制]
Code:
var foo = function(x,y){
alert(x+y);
}.$verify("number","number");
foo(1,2);
var foo2 = function(x,y){
x(y);
}.$verify(Function,"number");
//foo("error",2);
foo2(function(x){alert(x)},10);
//foo2("x","y");
var Class3 = function(x,y){
this.x = x;
this.y = y;
}.$verify("number","number");
Class3.prototype.dist2 = function(){return this.x*this.x + this.y*this.y};
var c = new Class3(10,20);
alert(c.dist2());
注意到上面这一段代码,$verify返回一个function,这个function是调用$verify的那个 function的一个第一范式迭代,这种处理方法在语法层面上达到很好的效果,而且它是无害的,这意味着你在编写和调试代码的时候可以得到$verify带来的好处,而在你发布代码的时候,你却可以很容易地用文本处理工具将$verify “尾巴”从你的代码中移出出去。
除此以外,第一范式的应用是很广泛的,因为它意味着你可以对函数进行任意扩展并且这些扩展不改变代码本身的语法结构!
你可以给函数增加某些不同功能的“尾巴”这些尾巴能够很好地帮你收集运行时信息、监视代码或者提供有用的调试信息。而这些所有的“尾巴”在你最终发布代码时,均可以非常方便地去掉,所以它们对实际运行的代码不会带来任何性能上的开销!这一点,对于开发者来说,无疑是非常非常好的消息!
第二范式:new T <=> T.apply(T.getPrototypeObject())
在几个月或者一年以前,我就在思考一个问题,我们知道,对于一个function T,脚本既可以把它当作一个方法来执行,又可以把它作为一个类型来构造,然而它们是不同的。除了new之外,其中语法上最显著的一个区别是T作为一个 function,既可以用()来直接操作,也可以享受call和apply带来的好处。而new,则受到比较大的限制,例如:
[复制]
Code:
function List()
{
this.members = Array.prototype.slice.apply(arguments); //Array支持可变参数,因为它可以作为函数来调用
}
function $list()
{
return new List(/*这里的参数应该怎么传?如果我希望$list(1,2,3...) <=> new List(1,2,3...)*/);
}
我们看到,相对function来讲,new操作受到较大的限制,当然上面这个实际问题是可以通过别的方式来解决的,但是用第二范式,无疑可以具有通用性地解决此类问题:
[复制]
Code:
G.objectAsPrototype = function(obj, c){
c = c || function(){};
c.prototype = obj;
return c;
};
Function.prototype.getPrototypeObject = function(){
var p = this.__templete__ || (this.__templete__= G.objectAsPrototype(this.prototype));
return new p();
};
Function.prototype.createInstance = function(){
var p = this.getPrototypeObject();
this.apply(p,arguments);
return p;
};
我们看到,第二范式解决了这样的问题,它告诉我们,JavaScript的new T操作等价于通过T的prototype创造一个“原型”对象,再用这个对象去执行T的构造函数,最终等价于产生了一个T的实例,但区别是后者不同于 new,是以一种函数调用的标准形式来产生的。
利用第二范式,我们可以很容易地增强JavaScript的原型继承,轻易地解决原型继承中关于构造函数延迟执行的需求(具体的将在另外一篇文章《深度探索高效率JavaScript继承》给出详细说明)
下面给出简单代码:
[复制]
Code:
Function.prototype.$pextends = function(p){
var me = this;
var ins = function()
{
this.$super = function(){
p.apply(this, arguments);
}
me.apply(this, arguments);
}
ins.prototype = p.getPrototypeObject();
return ins;
}
第三范式:new T <=> T.apply || new T(T.apply)
记得之前有人问过我一个有意思的问题,是关于js核心对象的扩展的。那个需求是实现一个自定义的Date类型MyDate,并且这个MyDate的所有构造参数都要和Date完全一致。之前,这个问题在解决的时候遇到一个困扰,具体的是这样的:
[复制]
Code:
function MyDate()
{
var ins = new Date(/*原生对象的扩展方式,可是如何处理可变参数呢?*/);
......
return ins;
}
而第三范式的意思是说,对于所有的核心对象,都满足如下两种情况之一:要么函数调用的返回结果等效于new操作,要么函数调用的返回结果利用new构造后等同于原始的new操作。Date的问题满足后者,也就是说,对于这个问题,将上面的代码改写成如下:
[复制]
Code:
function MyDate()
{
var ins = new Date(Date.apply(this, arguments));
......
return ins;
}
即可满足需求。
显然,这个第三范式并不是一个JavaScript类型默认遵循的范式,不过,有趣的是,几乎所有的核心对象都遵循第三范式:
Array、Function 满足范式右侧的第一个条件
Number、Boolean、String、Date、RegExp 满足范式右侧的第二个条件
所以,利用第三范式,我们可以实现核心对象的继承方法(关于核心对象继承的详细内容也会在《深度探索高效率JavaScript继承》给出详细讨论):
[复制]
Code:
Function.prototype.$cextends = function(p){
var me = this;
return function()
{
var ins = p.apply(this, arguments);
ins instanceof p || (ins = new p(ins));
me.apply(ins,arguments);
return ins;
}
}
除了继承核心对象之外,第三范式还有其他很有趣的应用:
[复制]
Code:
var MyFunction = function(){
this.m = function(){alert("static m")}
this.prototype.m = function(){alert("m")};
}.$cextends(Function);
//简单实现的Function Template
var X = new MyFunction("alert(1)");
var x = new X();
X.m();
x.m();
上面这段代码实现了一个自定义的函数模版,这样使用者就能够很方便地自己扩展Function,这个模式的意义是让Function元类具备有扩展能力,这种能力正是Meta-Programming所需要的。
发表评论
-
JEECG 了解感悟小过程
2013-05-19 14:52 1021相识: 第一次接触和了解jeecg的地方是ite ... -
长期更新开源项目
2012-09-05 23:09 9181。一款js库,用于处理xml 地址:http://code. ... -
eclipse几款必备的插件
2012-06-14 13:06 11631.Checkstyle CheckStyle是SourceF ... -
jad 工具
2012-06-14 10:48 935jad是eclipse的插件,,,可以反编译jar文件。 h ... -
java自带小工具 jvisualvm.exe
2011-10-27 11:23 1174JDK中还藏着一个宝贝,它的名字叫做VisualVM。Visu ... -
关于aop的功能
2011-10-15 16:50 785hi, 这个是关于异常处理的一些问题。。 ... -
groovy plugin
2011-09-08 15:39 748要先安装TestNG 1)在help->soft ... -
Struts2的深入分析
2011-07-28 09:15 729struts2的重要理解 点击这个链接,你将对str ... -
Java 中的中文编码问题
2011-07-19 15:55 638一篇很透彻的关于中文编码问题的讲解 http://www.i ... -
url传递参数中有特殊字符
2011-07-08 21:34 899有些符号在URL中是不能直接传递的,如果要在URL中传递这 ... -
Jquery AJAX POST和GET区别
2011-06-24 10:33 8901:GET访问 浏览器 认为 是等幂的 就是 一个相同的UR ... -
一个有用的快捷键
2011-06-21 16:16 642alt + tab 组合 window 系统非常的有用 可以在 ... -
ava.lang.ClassNotFoundException: org.apache.catalina.loader.DevLoader
2011-05-05 10:03 8675好多基于SSH 的旧系统还有人员在辛苦维护着 厂家给的代 ... -
myeclipse 快捷键 ctrl+o
2011-04-11 11:24 876ctrl+o,是快速搜索方法名。。 快速定位方法 ... -
java有趣的代码
2011-04-08 10:27 1255package org.java.funning; /** ... -
memcached的查看说明
2011-03-03 13:21 792memcached的查询手册,查看memcached是否安装成 ... -
netty框架的学习
2011-02-09 15:13 844netty一个socket通讯框架,由jboss公司开发 h ... -
jdk,jre,jvm
2010-12-21 13:04 796http://java-mzd.iteye.com/blog/ ... -
servlet3.0
2010-12-13 10:20 1174作为 Java EE 6 体系中重要成员的 JSR 315 规 ... -
java6 下面的exe文件
2010-12-09 17:12 1403补充详细: javac.exe ...
相关推荐
Thinking in Java4-课程代码code
Thinking in C++ 的习题答案, 只有Volumn I的, 谁有Volumn II的,请共享一下. 第一次发布资源,不知道分是否要的合适.
thinking-in-java-侯捷翻译版
Thinking-in-Java-4th-Edition习题答案
NULL 博文链接:https://i8i8i8.iteye.com/blog/445946
Thinking in Java Patterns learn J2EE
第四版英文版,非扫描格式
资源分三部分,只要全部下载,然后根据提示解压即可。thinking in java 是著名的java初学入门资料,如果需要可随便下载,祝各位有志青年,飞黄腾达。。。,
thinking-in-java thinking-in-java
thinking in java 是著名的java初学入门资料,如果需要可随便下载,祝各位有志青年,飞黄腾达。。。,最后一部分,下载完后大功告成!!!
Thinking In Java-Java 编程思想(中英文版 第四版) Thinking In Java-Java 编程思想(中英文版 第四版)
Computational-Thinking-and-Programming-Design 运算思维与程式设计
Computation-Thinking-and-Programming-Design 运算思维与程式设计
C++编程思想-Thinking in C++
第四版-Thinking+In+Java-练习题答案
[Bruce.Eckel编程思想系列丛书].PRENTICE_HALL-Thinking_In_Python-177ye
thinking_in_java-master.zip
这是这本书的第二部分,下载后根据提示解压
thinking in c++ 英文版 第一卷 第二卷
C++编程思想第2卷--Practical Programming(thinking in C++)