javascript 中对象的继承〔转贴〕


Posted in Javascript onJanuary 22, 2007

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属性,还得特殊处理。
  以前我比较过dojo和prototype.js中继承的实现,现在我明白个道理。对于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的时间注册吧(中文版),更加复杂,估计很多人像我一样,对于dojo暂时持观望态度。
如果你看过的前篇关于闭包的介绍,可能见过以下代码。
看以下代码前我想表述一个观点,任何网页中元素,浏览器都会为你创建一个对象(见)。(我觉得)这些对象与你建立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.
}

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

Javascript 相关文章推荐
如何快速的呈现我们的网页的技巧整理
Jul 01 Javascript
Mootools 图片展示插件(lightbox,ImageMenu)收集集合
May 21 Javascript
基于jQuery的可以控制左右滚动及自动滚动效果的代码
Jul 25 Javascript
基于jquery的3d效果实现代码
Mar 23 Javascript
正则表达式中特殊符号及正则表达式的几种方法总结(replace,test,search)
Nov 26 Javascript
解析JavaScript中instanceof对于不同的构造器或许都返回true
Dec 03 Javascript
JavaScript &amp; jQuery完美判断图片是否加载完毕
Jan 08 Javascript
浅谈原型对象的常用开发模式
Jul 22 Javascript
jquery鼠标悬停导航下划线滑出效果
Sep 29 jQuery
JS实现验证码倒计时的注册页面
Jan 02 Javascript
Vue scrollBehavior 滚动行为实现后退页面显示在上次浏览的位置
May 27 Javascript
JS变量提升原理与用法实例浅析
May 22 Javascript
利用javascript中的call实现继承
Jan 22 #Javascript
Javascript里使用Dom操作Xml
Jan 22 #Javascript
幻宇的层模拟窗口效果-提供演示和下载
Jan 20 #Javascript
写的htc的数据表格
Jan 20 #Javascript
共享自己写一个框架DreamScript
Jan 20 #Javascript
javascript读取RSS数据
Jan 20 #Javascript
一个多次搜索+多次传值的解决方案
Jan 20 #Javascript
You might like
PHP随机生成随机个数的字母组合示例
2014/01/14 PHP
PHP实现针对日期,月数,天数,周数,小时,分,秒等的加减运算示例【基于strtotime】
2017/04/19 PHP
PHP实现时间比较和时间差计算的方法示例
2017/07/24 PHP
JS 毫秒转时间示例代码
2013/09/22 Javascript
jQuery的load()方法及其回调函数用法实例
2015/03/25 Javascript
JQuery给网页更换皮肤的方法
2015/05/30 Javascript
非常实用的12个jquery代码片段
2015/11/02 Javascript
javascript精确统计网站访问量实例代码
2015/12/19 Javascript
vue分页组件table-pagebar使用实例解析
2020/11/15 Javascript
AngularJS 中的Promise --- $q服务详解
2016/09/14 Javascript
jquery判断类型是不是number类型的实例代码
2016/10/07 Javascript
js oncontextmenu事件使用详解
2017/03/25 Javascript
详解webpack进阶之插件篇
2017/07/06 Javascript
用Vue.js方法创建模板并使用多个模板合成
2019/06/28 Javascript
vue中如何实现后台管理系统的权限控制的方法步骤
2019/09/05 Javascript
[58:35]OG vs EG 2019国际邀请赛淘汰赛 胜者组 BO3 第二场 8.22
2019/09/05 DOTA
Python实现简单石头剪刀布游戏
2021/01/20 Python
python实现nao机器人身体躯干和腿部动作操作
2019/04/29 Python
Django框架下静态模板的继承操作示例
2019/11/08 Python
torch 中各种图像格式转换的实现方法
2019/12/26 Python
python如何解析复杂sql,实现数据库和表的提取的实例剖析
2020/05/15 Python
英国电子产品购物网站:TobyDeals
2018/07/30 全球购物
英国著名书店:Foyles
2018/12/01 全球购物
自1926年以来就为冰岛保持温暖:66°North
2020/11/27 全球购物
安全教育心得体会
2013/12/29 职场文书
2014年三万活动总结
2014/04/26 职场文书
政府门卫岗位职责
2014/04/29 职场文书
经理任命书模板
2014/06/06 职场文书
搞笑车尾标语
2014/06/23 职场文书
党员对照检查材料思想汇报(党的群众路线)
2014/09/24 职场文书
党的作风建设心得体会
2014/10/22 职场文书
简短的36句中秋节祝福信息语句
2019/09/09 职场文书
Django分页器的用法你都了解吗
2021/05/26 Python
js 数组 fill() 填充方法
2021/11/02 Javascript
Java界面编程实现界面跳转
2022/06/16 Java/Android
服务器SVN搭建图文安装过程
2022/06/21 Servers