诡异的delete

2010-03-31 by zhenn 发布在 javascript | 标签:

delete这个操作符呢,在javascript中不是很常用,但是他的特性的确很诡异。

1,删除对象的属性,代码:

  1. var o = {
  2.     a: 1,
  3.     b: 2   
  4. };
  5. delete o.a;
  6. alert(o.a)//undefined

那么到底delete删除的是对象的属性还是对象的属性值呢,我开始觉得删除的应该是值,因为结果是undefined,而没有报错。但是事实上,我的看法是错误的,举例说明:

  1. var o = {};
  2. var a = { 
  3.     pro: "zhenn" 
  4. };
  5. o.c = a;
  6. delete o.c;    //删除对象o的属性a
  7. console.log(o.c);     // undefined
  8. console.log(a.pro);   // zhenn

通过上述代码,不难看出在delete o.c之后呢,并没有删除o.c所指向的值,也就是对象a依然存在,否则a.pro应该是过不了编译这关的。说到这里,可以这么理解delete删除对象的属性,其实相当于删除了对对象中属性值的引用而已,但是这个值依然在对象栈中!

2,对数组的操作,先看代码:

  1. var arr = [1,2,3];
  2. delete arr[2];
  3. console.log(arr.length)// 3
  4. console.log(arr);   // [1,2,undefined]

又一次证明了,delete并没有真正删除元素,只是删除了元素所对应的键值。为了更进一步认清delete的本质,和Array中的pop方法比较一下。如下:

  1. var arr = [1,2,3];
  2. arr.pop();
  3. console.log(arr)// [1,2]
  4. console.log(arr.length)  // 2

这下应该真相大白了。

3,以上对对象和数组的操作,还很好理解,但是对于变量的操作,难免让人琢磨不透,代码如下:

  1. var a = 1;
  2. delete a;
  3. alert(a); // 1
  4.  
  5. function fn(){ return 42; }
  6. delete fn;
  7. alert(fn())// 42
  8.  
  9. b = 2;
  10. delete b;
  11. alert(b)// b is not defined;

很难解释通啊,同样是全局变量,用var声明的竟然删除不了,而直接声明的变量b竟然可以删除,不能不说delete很诡异了,在ECMA给出的解释中,也仅仅是说通过var声明的变量和通过function声明的函数拥有DontDelete特性,无法被删除。

关于javascript作用域

2010-03-18 by zhenn 发布在 javascript | 标签: ,

今天一个挚友给我出了道javascript笔试题,代码如下:

  1. function test(){
  2.     var a = b = 2;
  3. }
  4. test();
  5. alert(b);
  6. alert(a);

我看到这段代码,我笑了,很自信的回答道,会报错,因为a,b都是局部变量,所以a and b is not defined。然后我朋友笑了,迷惑ing,难道我错了吗?迟疑了10几秒,原来a是局部变量,而b没有在test中声明,故而是全局变量,很显然,在这种情况下,执行情况应该是b=2,a is not defined;后来想想,自己还真是缺乏点思维的严谨性啊,特发此贴,以儆效尤!

计算字符串中出现次数最多的字符和出现的次数

2010-02-22 by zhenn 发布在 javascript | 标签: ,

“计算出字符串中出现次数最多的字符是什么,出现了多少次?”

看到这个需求,我想大多数人应该首先想到的是转换成数组,再做处理,当然是可以解决问题的,然后这里提供一个巧妙的算法设计,无需转数组,可以很快解决问题,代码如下:

  1. var str = "adadfdfseffserfefsefseeffffftsdg";
  2. var maxLength = 0;
  3. var result = "";
  4. while(str!=''){ 
  5.     oldStr = str;
  6.     getStr = str.charAt(0);
  7.     str = str.replace(new RegExp(getStr,"g"),"");
  8.     if( oldStr.length-str.length > maxLength){
  9.         maxLength = oldStr.length-str.length;
  10.         result = getStr + "=" + maxLength;
  11.     }
  12. }
  13. alert(result);

zLib1.0.1发布

2010-01-09 by zhenn 发布在 javascript | 标签: , ,

世界上的事儿,从来都是没有定论的,既定的目标也未必能如愿,可能就是在你离目标越来越近的时候,会遇到另外一个选择,逐渐让你和目标渐行渐远。关于这点,写zLib的过程就是一个实实在在的例子!

写zLib的初衷只是想总结一些平时自己常用的函数,以便加快前端开发的进程,并不敢想象成就一个真正的JavaScript框架。但是在这个过程中,考虑到时下正流行的OOP,自己也难免落入俗套,于是设计理念转向了OOP,呵呵,虽然JavaScript不能算是一门面向对象编程的语言,只是基于对象而已,但是它特有的灵活度,完全可以模拟出来所谓的OOP。这样一来,本来三两天就可以搞定的事情,足足耗费了我一个月的时间(当然是工作之余),加上最后编写这个API文档,可真是觉得有些费时费力了。

说说zLib的特性:

1,简约快速的CSS选择器

2,DOM扩展:

zLib的主要内容,众所周知,javascript主要应用于Web开发,那么浏览器端环境里的DOM当然是每个框架的首要扩展目标,如果zLib不提供DOM扩展,那真的是一无是处了。

3,动画

4,非侵入式调用,相信用户很痛恨Dojo的这一点

5,保持和原生对象一致,即没有对JavaScript原生对象进行原型扩展,套用一句名言:“不要修改原生对象的prototype,除非你认为必要。”

6,提供完美的兼容方案,zLib兼容市场目前的主流浏览器:Internet Explorer6+, Mozilla Firefox 2, Safari 2+, Chrome, Opera 9+, 及其他基于IE内核的浏览器如Maxthon、360、Sogou等。

7,简易ajax的实现

可以实现很时髦的链式调用,如果觉得这种写法会使代码可读性降低,当然可以采用分段式写法,这个完全由个人喜好所决定!

诚然,zLib到目前为止,不能算是js framework,因为它不具备其他第三方程序库强悍的功能,我只把他当做自己的library来使用,但是如果zLib有幸被你下载并使用,那么这个API文档将会对你十分有帮助,因为利用它,你可以轻松的调用zlib的内部定义的方法来帮你完成手头上的任务,而不必在意这个方法究竟是怎么实现的。

立即体验

javascript设计模式学习笔记之“类式继承”

2009-12-26 by zhenn 发布在 javascript | 标签: ,

在做一件事情之前,首先要清楚做这件事情的好处有什么,相信不会有哪个人愿意无缘无故的去做事情。一般说来,我们在设计类的时候,实际上就是希望能减少重复性的代码,使用继承可以完美的做到这一点,借助继承机制,你可以在现有类的基础上再次进行设计并且充分利用它们已经具备的各种方法,而对设计的修改也更为轻松。废话不多说了,举例说明:

  1. function Person(name){
  2.     this.name = name;
  3. }
  4. Person.prototype.getname = function(){
  5.     return this.name;
  6. }
  7.  
  8. function Bloger(name,blog){
  9.     Person.call(this,name);
  10.     this.blog = blog;
  11. }
  12. var bloger = new Bloger("zhenn","http://www.men-ideal.com");
  13. alert(bloger.name=="zhenn");   /*返回ture*/
  14. alert(bloger.blog)   /*提示http://www.men-ideal.com*/
  15. alert(bloger.getname()=="zhenn");   /*提示"bloger.getname is not a function"*/

通过上例可以看到,Bloger在其内部通过call动态调用了其父类Person的原生属性和方法(关于call的讲解请参考),即可以理解为Bloger继承了Person,成为它的一个子类,但是细心的同学会发现,Person原型对象中的方法,仅仅依靠call,是不能继承过来的,这也就是会提示”bloger.getname is not a function”的原因所在了。不过不用担心,对上述代码稍作处理,即可解决这个问题!

  1. function Person(name){
  2.     this.name = name;
  3. }
  4. Person.prototype.getname = function(){
  5.     return this.name;
  6. }
  7.  
  8. function Bloger(name,blog){
  9.     Person.call(this,name);
  10.     this.blog = blog;
  11. }
  12. /*请注意以下两行代码*/
  13. Bloger.prototype = new Person();  
  14. Bloger.prototype.constructor = Bloger;
  15.  
  16. var bloger = new Bloger("zhenn","http://www.men-ideal.com");
  17. alert(bloger.name=="zhenn");   /*返回ture*/
  18. alert(bloger.blog)   /*提示http://www.men-ideal.com*/
  19. alert(bloger.getname()=="zhenn");   /*提示true*/

在这里需要对这两行代码解释一下,我们知道,每一个构造函数都有一个prototype属性,这个属性指向该构造函数的原型对象,其实原型对象也是实例对象,只不过在原型对象中定义的属性和方法可以提供给所有的实例对象共享,由此可以得出,新添加两行代码的意图就是设置子类的原型对象指向父类的一个实例化对象,而父类的实例化对象会把父类的原型属性方法统统继承过来,这样也就达到了我们的目的,子类的原型继承了所有父类实例对象具有的属性和方法。

但是还应该注意Bloger.prototype.constructor = Bloger;这行代码,因为把子类的prototype设置为父类的实例时,其constructor属性会指向父类,所以要设置子类原型的constructor重新指向子类,至此,已经完美实现了javascript的类式继承!

为了简化子类的声明,可以把扩展子类的整个过程写在一个名为extend的函数中,作用就是基于一个给定的类结构去创建一个新的类:

  1. function extend(childClass,parentClass){
  2.     var F = new Function();
  3.     F.prototype = parentClass.prototype;
  4.     childClass.prototype = new F();
  5.     childClass.prototype.constructor = childClass;
  6. }

有了这个extend这个函数,就可以很方便的扩展子类了,只需调用这个函数即可,上述添加的两行代码可改为extend(Bloger,Person), 一样可以实现完全继承!

JavaScript日历控件

2009-12-24 by zhenn 发布在 javascript | 标签: , ,

由于项目需要,写了个日历控件,仿照windows的日历写的,可以添加备忘录,备忘录操作所存取数据,没有数据库的支持,只在js中建立一个数组来存储,故而在不刷新页面的情况下,可以进行添加查看备忘录操作,如需和服务器进行交互,使用ajax也十分的方便!

点击查看应用

JavaScript日历控件

封装选项卡

2009-12-07 by zhenn 发布在 javascript | 标签: ,

选项卡技术很常见,即使刚踏入前端开发的同学都会使用它去完成一些基本的任务。有一种情况值的考虑,假如在一个页面中多处出现同样的功能模块的应用,那么我们很自然的会想到,把这个功能写成一个function,然后用一个事件来驱动这个function,这个的思路看上去一切都没什么问题了,既体现的代码的重用和模块化,又可以很快的完成繁琐的工作任务。

事实上,这样处理确实带来很多的便利性,但是美中不足的地方在于,在每个操作对象上都要加上事件属性(onclick=”",onmouseover=”"等等),否则一经写好的function就无法奏效,在推尚结构和表现向分离(实际上是xhtml+css技术,用在此处颇有不妥)的今天,这样的结构是遭人唾弃的(起码我很BS), 问题的出现总会有完美的解决方案。

顺水推舟,如果创建一个构造类,把一切操作对象的属性作为参数传入这个类,并赋给这个类的一个私有属性,那么在这个类的实例对象中,执行初始化方法时,利用定位运算符(.)能很轻松的访问到操作对象的属性,从而进行一些必要的操作。这个Tab类的结构如下:

  1. function Tab(obj){
  2.     this.obj = obj;
  3. }
  4. Tab.prototype.init = function(){
  5.     var $para = this.obj;
  6.     var t1 = document.getElementById($para.id).getElementsByTagName($para.tag1);
  7.     var t2 = document.getElementById($para.id).getElementsByTagName($para.tag2);
  8.     this.$event = "on" + $para.eventType;
  9.     t1[0].className = "current";
  10.     t2[0].style.display = "block";
  11.     for(var i=0;i<t1.length;i++){
  12.         t1[i][this.$event] = (function(index){
  13.             return function(){
  14.                 for(var j=0;j<t1.length;j++){
  15.                     t1[j].className = "";
  16.                     t2[j].style.display = "";
  17.                 }
  18.                 this.className = "current";
  19.                 t2[index].style.display = "block";
  20.             }
  21.         })(i);
  22.     }
  23. }

利用这个Tab类,可以帮助我们很快捷的完成任务,而且仅仅需要二行代码,其中一行用来创建一个实例化的对象,之后进行初始化操作,这一切看上去都是那么的优雅(自己的看法 -.-)。

点击查看应用

神奇的call()

2009-12-02 by zhenn 发布在 javascript | 标签: ,

先看看关于call()的官方解释,“调用一个对象的一个方法,以另一个对象替换当前对象。”,看了这样的解释,或许让你更摸不着头脑了。看例子:

  1. var x = "我是全局变量";    //定义全局变量x
  2. function a(){         //定义函数类结构a  
  3.     this.x = "我是在函数类结构a中声明的哦";   
  4. }
  5. //定义普通函数,弹出当前指针所包含的变量x的值
  6. function f(){      
  7.     alert (this.x);
  8. }
  9. //返回值为“我是在函数类结构a中声明的哦”
  10. f.call(new a());

我的理解是,f.call(new a())就是把函数(其实也是对象)f复制到被调用对象“new a()”下面去解析,事实上和下面这段代码的解析结果一样:

  1. function a(){
  2.   this.x = "我是在函数类结构a中声明的哦";
  3.   alert(this.x);   
  4. }
  5. a();

只不过此时变量X的作用域不同而已,咿…看起来好像有点继承的味道哦,难道不是吗?在上例中,f完全被构造函数a的实力对象继承了,如果说这还不足以说明a.call(b)是一种继承模式,那么再看一个更具有继承味道的用法吧。

  1. function f(){   
  2.     this.a ="a";   
  3.     this.b = function(){   
  4.         alert("b");
  5.     }
  6. }
  7. function e(){   
  8.     f.call(this);    
  9. }
  10. var c = new e();
  11. alert(c.a)//弹出a
  12. c.b();    //弹出b

在这个例子中,只要会使用浏览器的朋友,都能看得出来e完全继承了f的属性和方法,否则是无法解释的,因为在e中并没有定义属性a和b,那么按常理推断在e的实例对象c中,并不会出现这两个属性。

可控制的左右移动

2009-12-01 by zhenn 发布在 javascript | 标签: ,

在此之前,针对页面中的这种效果,一直用sina的某高人写的脚本,因为写的真的不错,可扩展性很强,但是在ie8面世之后,却发现在ie8中不兼容,所有滚动元素只能在可视范围内滚动一次。

既然如此,这个脚本就不能再用了,毕竟随着win7被炒的越来越热,而ie8又预装在win7中,所以不得不考虑不兼容ie8了。无奈了,自己写个吧,呵呵,其实自己还是很懒的(能偷懒就偷懒),套用懒人图库的一句经典,“学会偷懒,并懒出境界是提高工作效率最有效的办法!”,好像是在为自己的懒惰找借口,又扯远了,勿怪 -.-! 贴图:

可控制的左右移动

查看效果

虽然扩展性行不是太好,但是应用还是比较简单滴,所有滚动参数都可以在滚动类(zhennScroll)的属性中设置(包括设置是否自动滚动),相信稍有javascript基础都可以看懂的。

七彩贪吃蛇

2009-11-23 by zhenn 发布在 javascript | 标签: ,

不得不承认,兴趣是激发人进步的最好催化剂。以前还没写过类似这样的东西,不过数月之前就很想把他写出来,由于时间的短缺,一直没有执行,直到这个周末,终于按捺不住写了这个“七彩贪吃蛇”,虽然功能很简单,但是对我来说,还是从中汲取了不少养分,或者说以前掌握的知识点记得更牢固了,要不怎么说实践是最好的老师呢!先看操作界面:

七彩贪吃蛇

操作方法如下:

  1. 点击“开始按钮”或者回车键开始游戏。
  2. 使用↑→↓←可控制蛇身前进的方向!
  3. 每得5分即可升级,速度也会相应加快,共12级!
  4. 如果操作不当,蛇身超过边界或者蛇头接触蛇身上任意一点,则会提示游戏失败,然后点击回车键,会重新加载游戏,所得积分和等级清零!
  5. 开始游戏后,请关闭此说明,以免在操作游戏时,使网页上下移动,影响游戏的效果!

进入游戏界面