posts - 7,  comments - 58,  trackbacks - 0

     Prototype的bind方法常常把许多学习它的人弄得糊糊涂涂,google和baidu一番后还是一塌胡涂!本人也如此;本人觉得它是个从“谜人”到“迷人”的方法。此文将发表个人对此方法的理解,希望能帮助大家成功渡“谜”,到达“迷人”的彼岸!
<html>
<head>
 <script src="prototype.js"></script> //@7
 <script type="text/javascript">
   /**********************************
    *
    *  实现渲染一个带有"上一页"和"下一页"的组件,点击"上一页",当前页减1,点击"下一页"当前页加1
    *
    */
   function PagesSystem(container){
     this.currentPage = 10; //当前页
     this.pageSysDiv = document.getElementById(container); //容器
    
     this.init = function() { //将组件画出来
       this.createPrePage();
       this.createNextPage();
     };
    
     this.changePage = function(evtObj) { //根据点击后传过来的参数决定是加1或是减1
        if(evtObj == "next") {
          this.currentPage += 1;
          alert("你已执行将当前页加1,现在当前页是:" + this.currentPage);
        }else if(evtObj == "pre"){
          //此处不作if(this.currentPage ==1) return;限制为了体现当传入的参数为"pre"时,下面的alert()一定会执行
          this.currentPage -= 1;
          alert("你已执行将当前页减1,现在当前页是:" + this.currentPage);
        }
      
     };
    
     this.createPrePage = function() {//创建上一页组件
       var _span = document.createElement("SPAN");
       _span.style.cssText = "margin-left:16px";
       var _a = document.createElement("A");
       _a.href = "#";
       _a.onclick = this.changePage; //@1 当点击此("上一页")铵钮时执行
       _a.innerText = "上一页";
       _span.appendChild(_a);
       this.pageSysDiv.appendChild(_span);
     };
    
     this.createNextPage = function() {//创建下一页组件
       var _span = document.createElement("SPAN");
       _span.style.cssText = "margin-left:16px";
       var _a = document.createElement("A");
       _a.href = "#";
       _a.onclick = this.changePage; //@2 当点击此("下一页")铵钮时执行
       _a.innerText = "下一页";
       _span.appendChild(_a);
       this.pageSysDiv.appendChild(_span);
     };
   
     this.init(); //执行初始化
   }
   function testUse(msg){//@3在提出问题环节用到
     alert(msg);
   }
   window.onload = function() {
     var ps = new PagesSystem("pageDiv");
   }
 </script>
</head>
<body>
  <div id="pageDiv"></div>
</body>
</html>

二、分析代码,提出问题,解决问题
1、无法传递参数问题。
   你细看@1和@2处,当前的代码实现是无法把"pre"和"next"参数传递过去,于是,当你运行例子,点击上一页或下一页,都是没信息alert出来的!
   这种情况,是很常见的。那么,如何实现将参数传过去。
   将@1处代码修改如下:
                    _a.onclick = function(){ //@1 当点击此("上一页")铵钮时执行
                         testUse("pre"); //参看@3
                         this.changePage("pre");
                    }
   这样创建一个匿名函数赋予_a.onclick,也就是当_a对象的onclick事件触发后将执行此匿名函数,而匿名函数将帮忙调用testUse("pre")和this.changePage("pre")两个方法,
   从而达成传递参数。
   修改代码,运行例子后点击上一页后会显示如下两个信息,一个是testUse中输出的信息,证明了实现参数传递,另一个却是运行错误提示。
   

   这是执行this.changePage("pre")方法抛出来的。它并没像我们预期想的运行。
   从提示获到的信息是,对象不支持此属性或方法(如果浏览器报的是中文提示就可以看到“对象不支持此方法或属性”的提示)
   回头看this.changePage("pre")方法,很明显this是错误提示中所指的对象,在本应用中指PagesSystem对象指针的引用,在应用中确实是声明了this.changePage("pre")方法,但为什么说没此方法呢????
2、在问题1中,我们已成功解决传递参数,但PagesSystem对象的changePage方法被谁偷了???
   再将刚才的代码修改如:
                     _a.onclick = function(){ //@1 当点击此("上一页")铵钮时执行
                       testUse("pre"); //参看@3
                       alert(this.tagName);
                       this.changePage("pre");
                    }
   再运行例子,你会发现输出this.tagName的值为 A, 它就是_a对象。噢,我的天啊。怎么会这样???
   哈哈..._a对象就是<a href=""/></a>这个html 元素对象,这里是“上一页”铵钮对象,原型中哪来changePage方法啊,所以报错!!!
   你可以这样理解,看如下代码:
     function PagesSystem(container){//此应用中的PagesSystem对象,changePage方法的上下文对象,也可以称为归属者。
       //...省略其它代码
       this.changePage = function(evtObj) { //根据点击后传过来的参数决定是加1或是减1
         if(evtObj == "next") {
           this.currentPage += 1;
           alert("你已执行将当前页加1,现在当前页是:" + this.currentPage);
         }else if(evtObj == "pre"){
           //此处不作if(this.currentPage ==1) return;限制为了体现当传入的参数为"pre"时,下面的alert()一定会执行
           this.currentPage -= 1;
           alert("你已执行将当前页减1,现在当前页是:" + this.currentPage);
         }
       };
       //...省略其它代码
     }
    
     这样的代码,你很容易看出this是指PagesSystem, 那么我们继续往下看
     假设 A对象的原型如下:
     function A() {//@4
       //...
        this.onclick;
       
        this.doClick = function() { //点击
          this.onclick();//执行
        }
      
       //...
     }
    
     当你在PagesSystem方法中
                   _a.onclick = function(){ //@1 当点击此("上一页")铵钮时执行
                       testUse("pre"); //参看@3
                       alert(this.tagName);
                       this.changePage("pre");
                    }
    写上这样的代码后,你可以离谱认为@4的代码的模样是如下:
    function A() {//@4
       //...
        this.onclick = function(){ //@1 当点击此("上一页")铵钮时执行
             testUse("pre"); //参看@3
             alert(this.tagName); //@5
             this.changePage("pre"); //@6
          };
       
        this.doClick = function() { //点击
          this.onclick();//执行
        }
       //...
     }
     呵呵。。如果这样看的话,@5,@6中的this当然是指a对象,没异义。那当然是没changePage方法。
    
3、那么如何解决这问题呢??
   很幸运,prototype.js中的bind方法就可以解决这样的问题,它还解决我们上面提的传参数问题。
   看bind大侠帅样:
  
   bind: function() {
    if (arguments.length < 2 && Object.isUndefined(arguments[0])) return this;
    var __method = this, args = $A(arguments), object = args.shift();
    return function() {
      return __method.apply(object, args.concat($A(arguments)));
    }
  }
  bind方法中的this就是bind方法的所属者(上下文)如: f.bind(),f是一个声明了的方法,那么bind 方法里的this就是f
  再细看,bind方法其实做的工作是返回一个匿名函数,此匿名函数帮忙执行this所指的方法(bind方法的所属者),如果你有如下代码
  function f(msg) {
    this.functionName = "f method";
    alert(msg);
    alert(this.functionName);
  }
 
  button.onclick = f.bind(this, msg); //这里的this指f, 在bind方法中用object = args.shift()获得,这样的话,当点击button后执行f方法, f方法中的this就不会无故被 button代替。^_^不然,会报错的啊,button哪来functionName,呵呵...
  它既解决将msg参数传过去,同时将f绑定到button环境下,bind方法得名可能就是这意义吧。至于如何实现将f绑定,靠的就是apply方法。
  apply谜人色彩就由你们自行去揭开啦!
  介绍了bind大侠给大家,我的例子就麻烦你们自己调通它啦。谢了。。
  
  欢迎交流指正。

 备注: 如需转载本文,请注明出处
    

posted on 2008-05-08 22:37 Sonny Li 阅读(1926) 评论(6)  编辑  收藏 所属分类: Prototype学习志

FeedBack:
# re: Prototype学习志 之 bind方法的“谜”迷人色彩!
2008-05-08 23:21 | 郑晖
如果在浏览器中debug javascript,建议用Firefox的Firebug,它比IE好得太多了。  回复  更多评论
  
# re: Prototype学习志 之 bind方法的“谜”迷人色彩!
2008-05-08 23:45 | 无羽苍鹰
嗯,,谢谢 ^^  回复  更多评论
  
# re: Prototype学习志 之 bind方法的“谜”迷人色彩!
2008-05-09 22:39 |
一楼建议不错。。前几天刚了解到。。  回复  更多评论
  
# re: Prototype学习志 之 bind方法的“谜”迷人色彩!
2008-07-30 11:31 | 杜东辉
本人到此一游,有好东东多分享一下呀,多姐!!!  回复  更多评论
  
# re: Prototype学习志 之 bind方法的“谜”迷人色彩!
2009-01-20 11:15 | fujw
挺 好  回复  更多评论
  
# re: Prototype学习志 之 bind方法的“谜”迷人色彩![未登录]
2012-10-03 16:11 | lc
我在IE中提示对象不支持“bind”属性或方法
请问这个是怎么回事呢?  回复  更多评论
  

只有注册用户登录后才能发表评论。


网站导航:
 
<2009年1月>
28293031123
45678910
11121314151617
18192021222324
25262728293031
1234567

常用链接

留言簿(3)

随笔分类

随笔档案

文章分类

相册

收藏夹

博客好友

搜索

  •  

最新评论

阅读排行榜

评论排行榜