zoukankan      html  css  js  c++  java
  • "跟我再深入啃啃prototype.js"

    http://www.blogjava.net/zkjbeyond/archive/2006/05/25/48069.aspx
    Quote:

    以下有些观点有些偏激.关于事件注册的相关模式我相信会很快出现的,偶正在研究中.

    1、关于javascript的apply和call函数

    prototype.js中用了大量的apply和call函数,不注意会造成理解偏差。
    官方解释:应用某一对象的一个方法,用另一个对象替换当前对象。
    apply与call的区别是第二个参数不同。apply是 数组或者arguments 对象。而call是逗号隔开的任何类型。

    apply,call方法最让人混淆的地方也是apply,call的特色。但最好不要滥用。
    能改变调用函数的对象。如下例,函数中用到this关键字,这时候this代表的是apply,call函数的第一个参数。

    <script src="prototype1.3.1.js"></script>
    <input type="text" id="myText" value="input text">
    <script>
    function Obj(){
    this.value="对象!";
    }
    var value="global 变量";
    function Fun1(){
    alert(this.value);
    }
    window.Fun1();
    Fun1.apply(window);
    Fun1.apply($('myText'));
    Fun1.apply(new Obj());
    </script>

    2、关于闭包
    prototype.js在Class.create,bind等中用到javascript的闭包特色。但整体上prototype.js对于强大的闭包特性用的不多。大家可以参阅我翻译的篇文章了解闭包
    3、让我比较反感的两个方法
    (1)
    var Class = {
    create: function() {
    return function() {
    this.initialize.apply(this, arguments);
    }
    }
    }
    很讨厌用别的语言的风格来写javascript。用这个方法构造自定义类 并没有觉得有多方便,减少代码行数,只会让人难理解,多定义一个initialize方法。
    其实讨厌这条有些牵强,不过修改Object的原型对象就有点过分了。
    (2)Object.prototype.extend
    先不过你取个extend的名字会让熟悉java的人引起的歧义。修改Object的prototype就说不过去了。不知道作者是怎么考虑的。当你for in循环对象是,麻烦就来了。可能有人会问你for in干吗。 我一个项目中既用了DWR,也用了prototype.js,dwr返回的javascript对象都多了个exetend属性,还得特殊处理。
    以前我比较过[URL=http://www.blogjava.net/zkjbeyond/archive/2006/05/08/45108.html]dojo和prototype.js中继承的实现[URL],现在我明白个道理。对于javascript这种没有静态类型检查,语法宽松的语言来讲,如果你选择了某个js类库,那你也必须适应作者写javascript的风格。prototype.js的作者对extend的使用炉火纯青,如果我们不当它只是个属性拷贝的函数的话,多读读prototype.js的代码是好的。
    4、关于函数的绑定
    类库提供了Function.prototype.bind Function.prototype.bindAsEventListener两个方法。首先我们从概念上解释一个这两个方法。
    任何一个函数都可以调用这两个方法;参数的是javascript对象或网页上元素对象;返回类型是个函数对象。
    本来我就是个函数,返回还是函数,到这两个函数有什么不同呢。看实现代码,关键还是apply\call函数的代码。其实这里只是转化了一下方法调用的对象。

    <script src="prototype1.3.1.js"></script>
    <input type=checkbox id=myChk name="asf" value=1> Test
    <script>
    var CheckboxWatcher = Class.create();
    CheckboxWatcher.prototype = {
    initialize: function(chkBox, message) {
    this.chkBox = $(chkBox);
    this.message = message;
    this.chkBox.onclick = this.showMessage.bindAsEventListener(this);
    },
    showMessage: function(evt) {
    alert(this.message + ' (' + evt.type + ')');
    }
    };
    new CheckboxWatcher('myChk','message!!!!');
    //$('myChk').onclick=function(){};
    </script>
    这是 https://compdoc2cn.dev.java.net/ 上举的例子,个人感觉没什么意思,反而让我对bind,bindAsEventListener有些反感。(javascript就是这样,明明大家都知道的语法,但写出来的代码差别确很大)
    看下面代码:

    <script src="prototype1.3.1.js"></script>
    <input type=checkbox id=myChk name="chk" value=1> Test
    <script>
    function Class(){
    this.name="class";
    }
    Class.prototype.getName=function(){
    alert(this.name);
    }
    var obj=new Class();
    //$('myChk').onclick=obj.getName;
    $('myChk').onclick=obj.getName.bind(obj);
    //$('myChk').onclick=obj.getName.bind($('myChk'));
    </script>

    从上面代码可以看出bind/bindAsEventListener只是包装了一下apply/call方法,改变方法的调用对象。如例子,你可以把obj.getName方法转化成任何对象调用,并且把方法让表单元素触发。(bind和bindAsEventListener之间只是返回函数的参数不同)
    这两个方法也可以用在对象之间的方法重用,实现类似继承方法的概念。看以下代码,其实是比较无聊的。

    <script src="prototype1.3.1.js"></script>
    <script>
    function Class1(name){
    this.name=name;
    }
    Class1.prototype.getName=function(){
    alert(this.name);
    }
    function Class2(name){
    this.name=name;
      this.getName=Class1.prototype.getName.bind(this);
    }
    var obj1=new Class2("yql");
    obj1.getName();
    var obj2=new Object();
    obj2.name="zkj";
    obj2.fun=Class1.prototype.getName.bind(obj2);
    obj2.fun();
    </script>


    我从来没读过prototype.js的扩展项目代码,也不知道bind..的最佳实践,一起挖掘吧。但你绝对不要把bind/bindAsEventListener从绑定的词义上来理解,可能会让你更加迷惑。从apply/call理解本质。应用某一对象的一个方法,用另一个对象替换当前对象。

    5、关于事件的注册

    <script src="prototype1.3.1.js"></script>
    <input type=checkbox id=myChk name="chk" value=1> Test
    <script>
    Event.observe(myChk, 'click', showMessage, false);
    //$('myChk').onclick=showMessage;
    //$('myChk').onclick=showMessage.bind();
    $('myChk').onclick=showMessage.bind($('myChk'));
    function showMessage() {
    alert(this.value);
    }
    </script>

    执行上面代码,你就能明白Event.observe与bind/bindAsEventListener之间的区别:
    (1) 显然Event.observe有限制,只能处理简单的函数,并函数中不能有this之类的东西。
    (2)Event.observe内部用到addEventListener/attachEvent。能把多个函数加到一个触发事件(window.onload)。bind是覆盖。

    6、关于事件监听最佳实践
    很显然prototype.js提供的事件注册方法不是很完善。那看看dojo的时间注册吧([URL=http://ajaxcn.org/space/Ajax/Dojo/Event]中文版[URL]),更加复杂,估计很多人像我一样,对于dojo暂时持观望态度。
    如果你看过的前篇关于闭包的介绍,可能见过以下代码。
    看以下代码前我想表述一个观点,任何网页中元素,浏览器都会为你创建一个对象([URL=http://www.blogjava.net/zkjbeyond/archive/2006/04/23/42666.html]见[URL])。(我觉得)这些对象与你建立javascript对象区别是它们有事件监听,会响应鼠标键盘的事件。如果你用了以下代码,那么把事件监听代码很好的转化到你的javascript代码中。

    function associateObjWithEvent(obj, methodName){
    return (function(e){
    e = e||window.event;
    return obj[methodName](e, this);
    });
    }
    function DhtmlObject(elementId){
    var el = getElementWithId(elementId);
    if(el){
    el.onclick = associateObjWithEvent(this, "doOnClick");
    el.onmouseover = associateObjWithEvent(this, "doMouseOver");
    el.onmouseout = associateObjWithEvent(this, "doMouseOut");
    }
    }
    DhtmlObject.prototype.doOnClick = function(event, element){
    ... // doOnClick method body.
    }
    DhtmlObject.prototype.doMouseOver = function(event, element){
    ... // doMouseOver method body.
    }
    DhtmlObject.prototype.doMouseOut = function(event, element){
    ... // doMouseOut method body.
    }

    有时间我想用以上思想实现一个网页浮动框拖拉的代码(其实已经有很多了),待续........





    引用:ajaxcn.org 链接。谢谢dlee


  • 相关阅读:
    C#项目中怎样创建和使用类和类库
    第一个存储过程程序
    C# 如何判断字符串中是否包含另一个字符串?
    word中怎么快速选中光标之前或之后的全部内容?
    DHL学习--<asp:literal
    ASP.NET后台怎么输出方法中间调试信息?
    联想THINKPAD E40的快捷键怎么关闭?哪些F1 F2 F3的键我需要用到 但是每次都按FN 太烦人了
    sql 参数化查询问题
    echarts地图 禁止高亮显示(转载)
    EChart中使用地图方式总结(转载)
  • 原文地址:https://www.cnblogs.com/dkblog/p/1980938.html
Copyright © 2011-2022 走看看