浏览模式: 标准 | 列表分类:Javascript
Submitted by gouki on 2009, August 11, 9:15 PM
不知道大家是否还记得08年的5月12日,那一天,所有的网页都是灰色的,纪念那逝去的生命。
对于网页开发者来说,为了让用户看到灰色的页面,大多数人都采取了直接修改CSS的方式,使得image的alpha通道为gray,然而,这个方法是不支持FF的。N多办法都不支持。
这是一个JS的特效。它有N多处理图片的方法,可以按需加载,网址是:http://www.nihilogic.dk/labs/imagefx/,可以看到一些效果。
根据网上提供的JS,下载下来后,直接src一下就能用了。然而在测试的时候只有IE有效,firefox下是无效的。打开firebug,发现在执行后报错:
开始的时候一直没有细看,发现上面写的是"code:"也没有什么代码。就利用firebug的watch功能监视。然而死活找不到问题。
代码与网络上是一模一样,问题在哪里呢?
再仔细看出错代码,发现,前两个单词居然是:Security error,难道是安全问题?FF对本地代码的执行进行了限制?
立马把代码拷到虚拟机下运行,果然一切正常。
唉。。。
原来我为了这样一个问题折腾了将近一周。不仔细看出错信息导致的呀。。
顺便贴一个开心网的BUG图片:
Javascript | 评论:0
| 阅读:16385
Submitted by gouki on 2009, August 11, 4:32 PM
DSL,不算新名词了。转至博客园,看名称,估计还有后续文章,先转载,相当于mark一下,哈哈。这样就不会以后找不到链接了。
作者是博客园的cat chen,原文地址,http://www.cnblogs.com/cathsfz/archive/2009/08/10/1543266.html
内容如下:
jQuery刚刚出来的时候,我没有太多关注它,觉得这不过是Yet Another JavaScript Library。早期的jQuery专注于DOM节点的筛选与操作,不提供众多的基础类扩展,更不提供UI组件,因此体积能够做到很小。然而,我实在看不 出它和我熟悉的Prototype比有什么明显的优势——jQuery能做的各项独立的操作,Prototype都能做。
后来用jQuery的人越来越多,并且大家都爱用它的链式方法调用,甚至还把这种写法推广到其它语言中去。例如ASP.NET MVP Omar AL Zabir就把他的服务器端C#组件设计为支持链式方法调用的。这时候我才开始关注jQuery,并且逐渐喜欢上了链式方法调用的写法,也在我自己的JavaScript组件中实现类似的API(参考Async和Overload)。最后,我突然明白到,这其实就是一种Internal DSL嘛!
在这篇文章里,我准备先讨论Internal DSL,在下一篇文章里面再解释为什么jQuery是Internal DSL。现在我们就从最根本的问题开始吧——
什么是Internal DSL?
DSL是指Domain Specific Language,也就是用于描述和解决特定领域问题的语言。例如说,我们有专门描述字符串特征的正则表达式,有专门描述数据库查询的SQL,有专门描述 XML结构的DTD和XSD,甚至有专门描述XML变换的XSLT,这些都是DSL。
当然,并非我们关注的领域都有现成的DSL,这时候我们有三个选择:
- 使用通用语言描述该领域的问题(non-DSL)
- 发明一门全新的语言描述该领域的问题(External DSL)
- 在一门现成语言内实现针对领域问题的描述(Internal DSL)
例如说,我们现在要描述一个很简单的金融领域问题,“我在花旗银行存款$200”这样一句话对应的三种法写法可能是:(假设已经存在I和CitiBank两个实体实例)
I.DepositTo(new USD(200), CitiBank); /* C# */
I deposit 200USD to CitiBank /* E-DSL */
I.deposit(200.USD()).to(CitiBank); /* I-DSL */
第1种做法的成本最低,你只需要有OO的思想就可以了,你总能把实体类设计出来,但可能和人类描述此领域问题的思维方式有一定偏差(为什么USD可以new?为什么不是deposit [something] to [somewhere]
?)。
第2种做法的成本最高,你需要写一个全新的解释器,至少是写一组全新的规则,然后让YACC这类工具帮你生成一个解释器,但这样出来的语法最贴近人类思维方式,甚至就如同自然语言一样流畅。
第3种做法术语上述两者的折中方案,如果语法不太复杂可以使用Builder模式实现语法分析,写出来的语法相当贴近自然语言,但还是有学习门槛。由于脚本语言有相当的灵活性,所以现在很多人倾向于选择在脚本语言内实现Internal DSL。
如何构造Internal DSL?
常见的两种Internal DSL实现方法是Method Chaining和Function Sequence。如果我们需要描述一台机器的硬件组成,两种实现方式的代码分别如下:
/* Method Chaining */
computer()
.processor()
.cores(2)
.i386()
.disk()
.size(150)
.disk()
.size(75)
.speed(7200)
.sata()
.end();
/* Function Sequence */
computer();
processor();
cores(2);
processorType(i386);
disk();
diskSize(150);
disk();
diskSize(75);
diskSpeed(7200);
diskInterface(SATA);
无论是哪一种写法,中间都必须写一个分析器层。就如同语法分析器需要使用状态机一样,Internal DSL的实现也必须内置一个状态机,以记录当前执行到什么状态了,并且接下来可以转移到哪些有效状态。
由于这不是一篇专门讲语法分析器和状态机实现的文章,所以我们把关注点保持在API层面就可以了,不深入讨论其实现细节和成本。我们知道链式方法调用能够实现Internal DSL就够了,至于jQuery是如何利用好这一点的,我们在下一篇文章里再作讨论。
小结
在这篇文章里,我们了解了Internal DSL与External DSL之间的区别,同时还了解到实现Internal DSL的具体方式,这为我们接下来讨论jQuery的Internal DSL式接口做好了铺垫。在下一篇文章里,我们将深入地来看看为什么jQuery的接口要如此设计,它能为用户带来了怎样的便利,同时它自身的实现上又有 什么优势。
如果你不希望错过下一篇文章,你可以考虑订阅我的博客:
Javascript | 评论:0
| 阅读:15654
Submitted by gouki on 2009, August 10, 10:26 PM
膘叔写在前面的话,关于memoization好象在jquery里被应用到了。但应该是1.2.6的事情了,最初的ajax是没有缓存的。后来增加了Data缓存。(记不清了,希望没有记错)
对于memoization的记忆大约是在07年,好象有一个red开头的国内的某个网站,把菲伯拉契数列用memoization实现了一遍,当时记得的测试结果,一个是3000多ms,一个是1000多ms,这已经不是一个量级的了。
于是后来,我看了一下,根据这个原理,写了一个gdata的cache,缓存一些我经常使用的函数和数据。现在当然是不用了。呵呵
以下是原文内容,它来自playgoogle的http://www.cssrain.cn/default.asp?id=1392:
最近在读《JavaScript 设计模式》一书,其中工厂模式中提到了memoizing技术,今天仔细整理了一下memoization 相关的资料,与大家共享。
memoization 一词是Donald Michie 根据拉丁语memorandum杜撰的一个词。相应的动词、过去分词、ing形式有memoiz、memoized、memoizing.
Memoization 是 一种将函数返回值缓存起来的方法,Memoization 原理非常简单,就是把函数的每次执行结果都放入一个键值对(数组也可以,视情况而定)中,在接下来的执行中,在键值对中查找是否已经有相应执行过的值,如 果有,直接返回该值,没有才 真正执行函数体的求值部分。很明显,找值,尤其是在键值对中找值,比执行函数快多了。现代 JavaScript 的开发也已经大量使用这种技术。
我们知道,在不同的浏览器中,xmlHttpRequest对象的具体实现都不同。需要判断何种浏览器以执行具体的方法。这里就有一个使用memoization来实现的例子。
- function createXHRObject = function(){
- //先把三个匿名函数缓存起来。
- var methods = [
- function(){return new XMLHttpRequest();},
- function(){return new ActiveXObject("Msxml2.XMLHTTP");},
- function(){return new ActiveXObject("Microsoft.XMLHTTP");}
- ];
- for(var i=0,len=methods.length;i<len;i++){
- try{//这里用try catch来代替了条件判断,通常我不赞成这种写法
- methods[i]();
- }
- catch(e){
- continue;//如果报异常,则执行下一次循环
- }
- // 把createXHRObject 与能正常执行的匿名函数对应起来,再调用createXHRObject不用再检测浏览器了
- createXHRObject = method[i];
- return method[i];
- }
- }
以上是一个简单的例子,第一次执 行createXHRObject()的时候,会循环判断methods 中的方法,获取一个能正确执行的,并将createXHRObject的引用指向这个方法。以后再使用这个方法的时候,不用去判断,直接自动获取正确的方 法。这省去了频繁的ajax调用中浏览器的检测。
当然,这个方法看上去效率的提升不是特别明显,我之所以写上来,是因为能比较清晰的理解memoization是如何实现的。在递归调用的时候,memoization的威力才能更好的显现。
一个递归的例子:
- function fib(n) {
- if (n < 2) {
- return n;
- }
- return fib(n - 1) + fib(n - 2);
- }
这是一个经典的斐波纳契序列,fib(20) 会把fib这个方法执行21891次,如果是fib(40),这会执行331160281次。
再看看如何使用memoization来实现,
- var iterMemoFib = (function() {
- var cache = [1, 1];
- var fib = function(n) {
- if (n >= cache.length) {
- //将一个递归转换成了一个
- for (var i = cache.length; i <= n; i++) {
- cache[i] = cache[i - 2] + cache[i - 1];
- }
- }
- return cache[n-1];
- }
- return fib;
- })();
将Function的原型扩展memoize 和unmemoize 方法,这样你可以对任何函数实现memoize和解除memoize,当然,这个方法要慎,对一些不是频繁执行的函数,没必要缓存:
- Function.prototype.memoize = function() {
- var pad = {};
- var self = this;
- var obj = arguments.length > 0 ? arguments[i] : null;
-
- var memoizedFn = function() {
- // 把参数作为数组保存,作为键,把函数执行的结果作为值缓存起来
- var args = [];
- for (var i = 0; i < arguments.length; i++) {
- args[i] = arguments[i];
- }
- if (!(args in pad)) {
- pad[args] = self.apply(obj, arguments);
- }
- return pad[args];
- }
- memoizedFn.unmemoize = function() {
- return self;
- }
- return memoizedFn;
- }
- Function.prototype.unmemoize = function() {
- alert("Attempt to unmemoize an unmemoized function.");
- return null;
- }
-
使用方法:
fib.memoize();
参考文档:
- Memoizing functions in JavaScript
- JavaScript Memoization
- 提升JS性能:将递归转换为迭代
- MemoizationFrom Wikipedia, the free encyclopedia
Javascript | 评论:0
| 阅读:16215
Submitted by gouki on 2009, August 7, 9:56 PM
我个人是觉得文章内的方法最有意思,既让代码显示在本页,又让这些代码不会被解析。以前我怎么没有想到过??(使用textarea来使代码完整存放在本页)
看来我的思维还是已经僵化了。。。
原文地址为:http://www.cnblogs.com/sanshi/archive/2009/08/07/1541380.html,是博客园sanshi的文章。
原文如下:
问题描述
有一个比较复杂的HTML片段(A),如果把这个HTML片段嵌入到其他页面中(B,C,D....)。
问题的关键是在HTML片段中有大量的JavaScript逻辑需要处理,比如说分页,点击事件响应等。
对于这个问题,我们用一个简单的例子来说明:
“页面上有一个按钮,点击此按钮引入一个HTML片段,此HTML片段中有分页按钮。”
1. 使用IFrame
主页面,点击一个按钮向页面引入一个IFrame:
XML/HTML代码
- <script type="text/javascript">
- $(function() {
- $("#clickToInsert").click(function() {
- $("#placeholder").html('<iframe src="iframe.htm"></iframe>');
- });
- });
- </script>
- <input type="button" id="clickToInsert" value="Insert HTML" />
- <div id="placeholder">
- </div>
IFrame页面,模拟分页的情况:
XML/HTML代码
- <script type="text/javascript">
- $(function() {
- var parent = $("#complex_page_segment");
- $(".previous", parent).click(function() {
- $(".content", parent).html("Previous Page Content");
- });
- $(".next", parent).click(function() {
- $(".content", parent).html("Next Page Content");
- });
- });
- </script>
- <div id="complex_page_segment">
- <input type="button" value="Previous Page" class="previous" />
- <input type="button" value="Next Page" class="next" />
- <div class="content">
- Page Content</div>
- </div>
2. AJAX返回页面片段,并注册事件
注:我们通过textarea来模拟返回的HTML片段。
XML/HTML代码
- <script type="text/javascript">
- $(function() {
- $("#clickToInsert").click(function() {
- $("#placeholder").html($("#clone").val());
- var parent = $("#complex_page_segment");
- $(".previous", parent).click(function() {
- $(".content", parent).html("Previous Page Content");
- });
- $(".next", parent).click(function() {
- $(".content", parent).html("Next Page Content");
- });
- });
- });
- </script>
- <input type="button" id="clickToInsert" value="Insert HTML" />
- <div id="placeholder">
- </div>
- <textarea id="clone" style="display: none;">
- <div id="complex_page_segment">
- <input type="button" value="Previous Page" class="previous" />
- <input type="button" value="Next Page" class="next" />
- <div class="content">Page Content</div>
- </div>
- </textarea>
由于我们需要在多个页面引用同一个HTML片段,这种方法导致大量事情处理被重复性的拷贝粘贴,明显我们需要将公共的方法提取出来。
3. AJAX返回页面片段,并调用页面片段中的函数注册事件
XML/HTML代码
- <script type="text/javascript">
- $(function() {
- $("#clickToInsert").click(function() {
- $("#placeholder").html($("#clone").val());
- init_complex_page_segment();
- });
- });
- </script>
- <input type="button" id="clickToInsert" value="Insert HTML" />
- <div id="placeholder">
- </div>
- <textarea id="clone" style="display: none;">
- <script type="text/javascript">
- function init_complex_page_segment() {
- var parent = $("#complex_page_segment");
- $(".previous", parent).click(function() {
- $(".content", parent).html("Previous Page Content");
- });
- $(".next", parent).click(function() {
- $(".content", parent).html("Next Page Content");
- });
- }
- </script>
- <div id="complex_page_segment">
- <input type="button" value="Previous Page" class="previous" />
- <input type="button" value="Next Page" class="next" />
- <div class="content">Page Content</div>
- </div>
- </textarea>
其实我们可以更进一步,完全没必要手工调用这个函数,而是可以在返回的HTML片段中让其自动执行。
4. AJAX返回页面片段,其事件自动注册
XML/HTML代码
- <script type="text/javascript">
- $(function() {
- $("#clickToInsert").click(function() {
- $("#placeholder").html($("#clone").val());
- });
- });
- </script>
- <input type="button" id="clickToInsert" value="Insert HTML" />
- <div id="placeholder">
- </div>
- <textarea id="clone" style="display: none;">
- <script type="text/javascript">
- $(function() {
- var parent = $("#complex_page_segment");
- $(".previous", parent).click(function() {
- $(".content", parent).html("Previous Page Content");
- });
- $(".next", parent).click(function() {
- $(".content", parent).html("Next Page Content");
- });
- });
- </script>
- <div id="complex_page_segment">
- <input type="button" value="Previous Page" class="previous" />
- <input type="button" value="Next Page" class="next" />
- <div class="content">Page Content</div>
- </div>
- </textarea>
最后一种方法和第一种IFrame的方式是我们所推荐的。
Javascript | 评论:1
| 阅读:18037
Submitted by gouki on 2009, August 4, 6:49 AM
链式调用,在PHP中使用的时候往往被人称作:连贯操作。
如果经常用ZF的人,会在Select类中很明显的看到这一点。目前连贯操作已经几乎被各大框架所引用(无非是以前不返回值,现在返回$this。哈哈)
以下是cssrain网站联盟中的karry(playgoogle)写的JS的连贯操作(链式调用),其实在jQuery中,这样的操作太常见了。
以下为全文内容:
用过jQuery的朋友一定对jQuery中方法的链式调用印象深刻,最近发布的YUI3也支持了方法的链式调用。这是一个非常不错的语法特性, 能让代码更加简洁、易读。很多时候链式调用可以避免多次重复使用一个对象变量,从而减少代码,而js是一种客户端执行的脚本语言,减少代码就减少了js文 件的大小,减少了服务器的压力。链式调用这么多优点,它是如何实现的呢?这篇文章就是想探讨一下这个问题。
链式调用例子如:$("p").append("test").fadeIn("fast");
看一段jQuery的源码:
append: function() {
return this.domManip(arguments, true, function(elem){
if (this.nodeType == 1)
this.appendChild( elem );
});
}
以上是jQuery中append方法的实现。append方法是向每个匹配的元素内部追加内容的方法,很明显,属于赋值操作,但是却有返回值,返回的是当前操作的dom(通常返回this指针)。这是链式调用的关键,你会发现这不过是个语法小技巧而已。
很明显,在赋值器方法中(或者本身没有返回值的方法中)很容易实现链式调用,而取值器相对来说不好实现链式调用,因为你需要取值器返回你需要的数据而不是this指针(当然,如果你坚持要实现链式方法,也可以用回调函数来实现)。
设计一个简单的支持链式调用的类:
JavaScript代码
- function Dog(name,color){
- this.name=name||"";
- this.color=color||"";
- }
- Dog.prototype.setName=function(name){
- this.name=name;
- return this;
- };
- Dog.prototype.setColor(color){
- this.color=color;
- return this;
- };
- Dog.prototype.yelp(){
- alert("我的名字叫:"+this.name+",我的颜色是:"+this.color);
- return this;
- };
使用方式:
JavaScript代码
- var dog = new Dog();
- dog.setName("旺财").setColor("白色").yelp();
取值器你也想支持链式调用?
那就用回调函数来实现,将本来应该返回的值直接传给回调函数,而return仍然返回this指针。接着上面的Dog类写一个方法:
JavaScript代码
- Dog.prototype.getName(callback){
- callback.call(this,this.name);
- return this;
- }
使用方式:
JavaScript代码
- function showName(name){
- alert(name);
- }
- dog.setName("旺财").getName(showName).setColor("白色");
Tags: 链式, 连贯操作
Javascript | 评论:0
| 阅读:20126