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 相关文章推荐
javascript 流畅动画实现原理
Sep 08 Javascript
jMessageBox 基于jQuery的窗口插件
Dec 09 Javascript
人人网javascript面试题 可以提前实现下
Jan 05 Javascript
jQuery输入框密码的显示隐藏【代码分享】
Apr 29 jQuery
用vue封装插件并发布到npm的方法步骤
Oct 18 Javascript
javaScript字符串工具类StringUtils详解
Dec 08 Javascript
JavaScript深拷贝和浅拷贝概念与用法实例分析
Jun 07 Javascript
详解webpack打包时排除其中一个css、js文件或单独打包一个css、js文件(两种方法)
Oct 26 Javascript
vue项目搭建以及全家桶的使用详细教程(小结)
Dec 19 Javascript
Vuerouter的beforeEach与afterEach钩子函数的区别
Dec 26 Javascript
JavaScript中0、空字符串、'0'是true还是false的知识点分享
Sep 16 Javascript
js实现选项卡效果
Mar 07 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 STRING 陷阱原理说明
2010/07/24 PHP
php 中英文语言转换类
2011/09/07 PHP
js限制checkbox勾选的个数以及php获取多个checkbbox的方法深入解析
2013/07/18 PHP
php小技巧之过滤ascii控制字符
2014/05/14 PHP
php中操作memcached缓存进行增删改查数据的实现代码
2014/08/15 PHP
php实现事件监听与触发的方法
2014/11/21 PHP
PHP register_shutdown_function()函数的使用示例
2015/06/23 PHP
php轻松实现文件上传功能
2016/03/03 PHP
php实现算术验证码功能
2018/12/05 PHP
javascript实现table表格隔行变色的方法
2015/05/13 Javascript
jQuery蓝色风格滑动导航栏代码分享
2015/08/19 Javascript
jQuery插件实现表格隔行变色及鼠标滑过高亮显示效果代码
2016/02/25 Javascript
浅谈JavaScript中小数和大整数的精度丢失
2016/05/31 Javascript
jQuery中ScrollTo用法示例
2016/09/04 Javascript
JavaScript定义数组的三种方法(new Array(),new Array('x','y')
2016/10/04 Javascript
jQuery ajax MD5实现用户注册即时验证功能
2016/10/11 Javascript
浅析上传头像示例及其注意事项
2016/12/14 Javascript
layui实现点击按钮给table添加一行
2018/08/10 Javascript
JS+HTML5 Canvas实现简单的写字板功能示例
2018/08/30 Javascript
vue如何在用户要关闭当前网页时弹出提示的实现
2020/05/31 Javascript
详解webpack的文件监听实现(热更新)
2020/09/11 Javascript
python实现socket端口重定向示例
2014/02/10 Python
详解python并发获取snmp信息及性能测试
2017/03/27 Python
用Python从0开始实现一个中文拼音输入法的思路详解
2019/07/20 Python
Python imread、newaxis用法详解
2019/11/04 Python
python通过函数名调用函数的几种场景
2020/09/23 Python
纯CSS3实现给头像加个光芒四射且旋转的背景动画效果
2014/05/07 HTML / CSS
HTML5中的拖放实现详解
2017/08/23 HTML / CSS
Ibood荷兰:互联网每日最佳在线优惠
2019/02/28 全球购物
opencv实现图像平移效果
2021/03/24 Python
优秀毕业生自荐信
2014/06/10 职场文书
厕所文明标语
2014/06/11 职场文书
中学生爱国演讲稿
2014/09/05 职场文书
办公室主任个人总结
2015/02/28 职场文书
社区公民道德宣传日活动总结
2015/03/23 职场文书
《雀魂PONG☆》4月1日播出 PV角色设定情报
2022/03/20 日漫