- 浏览: 141721 次
- 性别:
- 来自: 长沙
文章分类
最新评论
-
古尔丹之颅:
呵呵,现在呢?
有点沉重 -
我自闲庭信步:
大哥为什么我用你的方法想打开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 1085相识: 第一次接触和了解jeecg的地方是ite ... -
长期更新开源项目
2012-09-05 23:09 10351。一款js库,用于处理xml 地址:http://code. ... -
eclipse几款必备的插件
2012-06-14 13:06 12171.Checkstyle CheckStyle是SourceF ... -
jad 工具
2012-06-14 10:48 1048jad是eclipse的插件,,,可以反编译jar文件。 h ... -
java自带小工具 jvisualvm.exe
2011-10-27 11:23 1221JDK中还藏着一个宝贝,它的名字叫做VisualVM。Visu ... -
关于aop的功能
2011-10-15 16:50 829hi, 这个是关于异常处理的一些问题。。 ... -
groovy plugin
2011-09-08 15:39 795要先安装TestNG 1)在help->soft ... -
Struts2的深入分析
2011-07-28 09:15 803struts2的重要理解 点击这个链接,你将对str ... -
Java 中的中文编码问题
2011-07-19 15:55 675一篇很透彻的关于中文编码问题的讲解 http://www.i ... -
url传递参数中有特殊字符
2011-07-08 21:34 948有些符号在URL中是不能直接传递的,如果要在URL中传递这 ... -
Jquery AJAX POST和GET区别
2011-06-24 10:33 9341:GET访问 浏览器 认为 是等幂的 就是 一个相同的UR ... -
一个有用的快捷键
2011-06-21 16:16 734alt + tab 组合 window 系统非常的有用 可以在 ... -
ava.lang.ClassNotFoundException: org.apache.catalina.loader.DevLoader
2011-05-05 10:03 8747好多基于SSH 的旧系统还有人员在辛苦维护着 厂家给的代 ... -
myeclipse 快捷键 ctrl+o
2011-04-11 11:24 937ctrl+o,是快速搜索方法名。。 快速定位方法 ... -
java有趣的代码
2011-04-08 10:27 1297package org.java.funning; /** ... -
memcached的查看说明
2011-03-03 13:21 875memcached的查询手册,查看memcached是否安装成 ... -
netty框架的学习
2011-02-09 15:13 879netty一个socket通讯框架,由jboss公司开发 h ... -
jdk,jre,jvm
2010-12-21 13:04 848http://java-mzd.iteye.com/blog/ ... -
servlet3.0
2010-12-13 10:20 1210作为 Java EE 6 体系中重要成员的 JSR 315 规 ... -
java6 下面的exe文件
2010-12-09 17:12 1444补充详细: javac.exe ...
相关推荐
《Thinking in Java》是Bruce Eckel的经典之作,第五版(The Class object)主要探讨的是类对象(Class object)这一核心概念。在Java编程语言中,类对象是与类相关的特殊对象,它提供了对类信息的访问,包括类的元...
《Thinking in C++》是一本深受程序员喜爱的C++学习指南,由Bruce Eckel编写,旨在帮助读者深入理解和掌握C++编程语言。该书分为两卷,第一卷主要介绍了C++的基础知识,包括面向对象编程的基本概念,而第二卷则更...
《Thinking in Java》是Bruce Eckel的经典之作,它深入浅出地介绍了Java编程语言的核心概念和技术。本压缩包文件的标题“thinking in java2-3”表明内容涵盖了该书的第二部分,通常包括面向对象编程的深入探讨,可能...
《Thinking in Java》是Java编程领域的一本经典著作,由Bruce Eckel撰写,被誉为学习Java的必读之作。这本书深入浅出地介绍了Java语言的核心概念和技术,为初学者提供了全面而扎实的学习路径。"Thinking in Java 3-3...
本压缩包文件"thinking-in-cpp-2.zip"包含了第二卷的内容,为学习C++的开发者提供了宝贵的资源。 第一卷主要涵盖了C++的基础知识,包括基本语法、数据类型、控制结构、函数、类和对象等主题。其中,"thinking"这一...
Thinking In Java-Java 编程思想(中英文版 第四版) Thinking In Java-Java 编程思想(中英文版 第四版)
《Thinking in Patterns with Java》是一本深度探讨Java编程思想与设计模式的经典著作,旨在帮助开发者理解和运用各种设计模式,从而提升软件开发的效率和质量。这本书深入浅出地讲解了如何在Java环境中实现和应用...
《Thinking in Java》是Java编程领域的一本经典著作,由Bruce Eckel撰写,深受程序员喜爱。这本书深入浅出地介绍了Java语言的基础知识和高级特性,是初学者和进阶者的重要参考材料。从提供的信息来看,你可能已经...
《Thinking in Java 4》是 Bruce Eckel 编著的一本经典Java编程教材,它深入浅出地介绍了Java语言的核心概念和技术。这个压缩包“Thinkinjava4-code”包含了该书第四版对应的课程代码,是学习和理解书中理论知识的...
C++编程思想-Thinking in C++
总的来说,这份“Thinking-in-Java-4th-Edition习题答案”涵盖了Java编程的广泛领域,从基本语法到高级特性,从理论到实践,是提高Java技能的宝贵资源。通过解决这些习题,你不仅可以巩固所学知识,还能锻炼解决问题...
这个是我花钱买的,现在献给大家......
《Thinking in C++》是一本深受程序员喜爱的经典C++教程,由Bruce Eckel撰写,旨在帮助读者深入理解和掌握C++编程语言。这本书以其全面、深入和实用的特点,被广泛视为学习C++的必备参考书之一。《C++编程思想》是其...
《Thinking in Java》是Bruce Eckel的经典Java编程书籍,它为初学者和有经验的程序员提供了深入理解Java语言的全面指南。这本书强调了面向对象编程的概念,并通过丰富的实例来解释复杂的概念,使得学习过程更为直观...
《Thinking in Java》是由Bruce Eckel编著,侯捷翻译的Java编程经典教程。这本书深入浅出地介绍了Java语言的核心概念和技术,对于学习和理解Java编程有着极高的价值。在这个侯捷翻译的版本中,作者以清晰易懂的语言...
Thinking In Java- JAVA思考pdf版
《Thinking in Java》是Bruce Eckel的经典编程教材,第四版更是深受广大Java程序员喜爱。这本书以其深入浅出的讲解方式,全面系统地介绍了Java语言的核心概念和技术。在解答该书的练习题时,我们可以深入理解Java...
在“Computation-Thinking-and-Programming-Design-main”这个文件夹中,我们可以期待找到关于如何应用运算思维进行编程的实例和练习。可能包含的资源有: - Jupyter Notebook文件,其中包含了示例代码和逐步解释,...
《Thinking in Java》是Bruce Eckel的经典之作,第四版更是被广大Java开发者视为学习和进阶的必备书籍。这本书深入浅出地介绍了Java语言的核心概念和技术,包括面向对象编程、集合框架、多线程、网络编程、异常处理...
《Thinking in Java》是Bruce Eckel的经典编程教材,第三版(edition3)深入浅出地介绍了Java编程语言的核心概念和技术。这个压缩包文件包含了书中所提及的示例代码,名为"TIJcode",这对于理解和实践书中理论知识至...