JavaScript原型对象prototype
来源:http://justcoding.iteye.com/blog/1498561
JS中的phototype是JS中比较难理解的一个部分。javascript的方法可以分为三类:类方法,对象方法,原型方法。
例子:
obj1.func.call(obj)方法意思是将obj看成obj1,调用func方法。
prototype是什么含义
javascript中的每个对象都有prototype属性,Javascript中对象的prototype属性的解释是:返回对象类型原型的引用。
- A.prototype = new B();
理解prototype不应把它和继承混淆。A的prototype为B的一个实例,可以理解A将B中的方法和属性全部克隆了一遍。A能使用B的方法和属性。这里强调的是克隆而不是继承。可以出现这种情况:A的prototype是B的实例,同时B的prototype也是A的实例。
先看一个实验的例子:
-
1 function baseClass() 2 { 3 this.showMsg = function() 4 { 5 alert("baseClass::showMsg"); 6 } 7 } 8 9 function extendClass() 10 { 11 12 } 13 14 extendClass.prototype = new baseClass(); 15 instance = new extendClass(); 16 instance.showMsg(); // 显示baseClass::showMsg
我们首先定义了baseClass类,然后我们要定义extentClass,但是我们打算以baseClass的一个实例为原型,来克隆的extendClass也同时包含showMsg这个对象方法。extendClass.prototype = new baseClass()就可以阅读为:extendClass是以baseClass的一个实例为原型克隆创建的。
那么就会有一个问题,如果extendClass中本身包含有一个与baseClass的方法同名的方法会怎么样?
下面是扩展实验2:
-
1 function baseClass() 2 { 3 this.showMsg = function() 4 { 5 alert("baseClass::showMsg"); 6 } 7 } 8 9 function extendClass() 10 { 11 this.showMsg =function () 12 { 13 alert("extendClass::showMsg"); 14 } 15 } 16 17 extendClass.prototype = new baseClass(); 18 instance = new extendClass(); 19 20 instance.showMsg();//显示extendClass::showMsg 21
实验证明:函数运行时会先去本体的函数中去找,如果找到则运行,找不到则去prototype中寻找函数。或者可以理解为prototype不会克隆同名函数。
那么又会有一个新的问题:如果我想使用extendClass的一个实例instance调用baseClass的对象方法showMsg怎么办?
答案是可以使用call:
-
1 extendClass.prototype = new baseClass(); 2 instance = new extendClass(); 3 4 var baseinstance = new baseClass(); 5 baseinstance.showMsg.call(instance); //显示baseClass::showMsg
这里的baseinstance.showMsg.call(instance);阅读为"将instance当做baseinstance来调用,调用它的对象方法showMsg"。好了,这里可能有人会问,为什么不用baseClass.showMsg.call(instance);这就是对象方法和类方法的区别,我们想调用的是baseClass的对象方法。
最后,下面这个代码如果理解清晰,那么这篇文章说的就已经理解了:
1 <script type="text/javascript"> 2 function baseClass() 3 { 4 this.showMsg = function() 5 { 6 alert("baseClass::showMsg"); 7 } 8 9 this.baseShowMsg = function() 10 { 11 alert("baseClass::baseShowMsg"); 12 } 13 } 14 baseClass.showMsg = function() 15 { 16 alert("baseClass::showMsg static"); 17 } 18 19 function extendClass() 20 { 21 this.showMsg =function () 22 { 23 alert("extendClass::showMsg"); 24 } 25 } 26 extendClass.showMsg = function() 27 { 28 alert("extendClass::showMsg static") 29 } 30 31 extendClass.prototype = new baseClass(); 32 instance = new extendClass(); 33 34 instance.showMsg(); //显示extendClass::showMsg 35 instance.baseShowMsg(); //显示baseClass::baseShowMsg 36 instance.showMsg(); //显示extendClass::showMsg 37 38 baseClass.showMsg.call(instance);//显示baseClass::showMsg static 39 40 var baseinstance = new baseClass(); 41 baseinstance.showMsg.call(instance);//显示baseClass::showMsg 42 43 </script>
来源: http://www.nowamagic.net/javascript/js_KnowAboutPrototype.php
实例1: 文本自动取反
javascript中关于prototype的一个简单例子具体如下:prototype是javascript原型属性,通过这个属性我们可以扩展方法,以下例子主要通过给string增加取反属性,当调用这个方法时,文本自动取反
1 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 2 <html xmlns="http://www.w3.org/1999/xhtml" > 3 <head> 4 <title></title> 5 <script type="text/javascript"> 6 //定义自定义方法把文本写反 7 function outputbackwards(){ 8 for (i=this.length-1;i>=0;i--) 9 document.write(this.charAt(i)) 10 } 11 //给stirng增加自定义方法 12 String.prototype.writeback=outputbackwards 13 </script> 14 </head> 15 <body> 16 <script type="text/javascript"> 17 var message1="Welcome to my site!" 18 message1.writeback()//调用方法 19 var message2="Today is a beautiful day" 20 message2.writeback() 21 </script> 22 </body> 23 </html> 24
实例 2: 用 JavaScript 实现 jQuery 显示与隐藏动画
在 jQuery 中有 show(), hide(), slideDown(), slideUp() 等方法,能够以动画的形式显示或隐藏 DOM 元素。这一类的动画在页面交互中比较常用,这也是 jQuery 方便开发的地方之一,但如果只想使用这些动画效果而加载整个 jQuery 库那就有点浪费资源了,于是便尝试用原生的 JavaScript 实现这一类 jQuery 动画。
在介绍原生 JavaScript 代码前 Kayo 先想提出一个问题,也就是 jQuery 相对 JavaScript 的优势是什么?若开发者是先了解 jQuery 再学习原生 JavaScript ,那么以下这些优势将会让你很容易发现:
强大而且灵活的选择器, 正如很多 JavaScript 类库一样,jQuery 使用 $() 函数来作为选择器,支持 CSS1 到 CSS3 的选择器,比起 JavaScript 中的 document.getElementById(), document.getElementsByTagName() ,这样的选择器无疑方便很多。
带有常用的事件、方法,包括一些动画方法。
完善的封装, jQuery 中的对象处理,传递,操作都有着完善的封装和处理机制,并且做好了针对不同浏览器的兼容,这些若使用原生 JavaScript 重写将是一项非常繁重的工作。
当然, jQuery 的劣势也非常明显——即使你的整个网站只是使用 jQuery 的几个动画方法,也要加载一个近 100K 的库文件。下面大家不妨带着上面几点思考去阅读下文,这样就会感觉到 jQuery 在使用上的方便。
回到一开始讨论的问题——使用原生的 JavaScript 实现 jQuery 动画,下面会放出代码,但由于代码已经封装好了,具体的过程通过代码比较难理解,这里再简要说明一下:
1.建立一个动画对象—— Transform ,增加一些方法:
动画形式隐藏 DOM 元素
动画形式显示 DOM 元素
2.建立一个 DOM 元素对象—— $ ,增加一些方法:
获取某 id 的 DOM 元素
获取该元素的某项 CSS
动画形式隐藏元素(实例化 Transform 对象并调用其中的方法)
动画形式显示元素(实例化 Transform 对象并调用其中的方法)
3.根据实际需要操作的 DOM 元素 id 实例化 $ 对象并调用相应的方法
可以看出,上面的方法有点累赘,为什么不直接把动画方法写到 $ 对象里呢?
之所以会这样写,完全是为了方便维护和提高对象的独立性,例如给动画对象添加更多的动画方法或是给 Dom 元素对象添加更多的操作,封装为两个不同的对象将会更加方便维护。如果只是希望使用简单的动画效果,完全可以不同封装,毕竟封装后效率会降低很多,当然这种效率的差别你很难在 PC 上直接看出。
下面给出具体方法和代码:
实现动画的原理很简单——按特定的单位时间连续播放一组静态画面,在 JavaScript 中,我们可以利用 window.setTimeout 或 window.setInterval 来实现此效果,这里 Kayo 采用 window.setTimeout 递归调用一个减少元素宽度和高度的方法来实现。
需要注意的是:
在实现动画的方法中应该直接传递需要操作的 DOM 对象而不是传递 DOM 对象的 id ,因此我们最好写一个方法来获取 DOM 。
动画应该是能同时作用于网页上的多个元素,因此避免使用全局变量。
封装函数时应该使用 .prototype 添加方法,节省内存。
这些 JavaScript 写好后应该放在 footer 而不是 header ,因为原生 JavaScript 中没有自带的函数检查页面中每一个 DOM 是否都加载完毕,因此应该把 JavaScript 写在最后,当然开发者也可以另外写出一个判断页面的 DOM 是否加载完毕的函数。
这里以隐藏 DOM 元素为例,创建一个动画对象,包含以动画形式隐藏 DOM 元素的方法。在动画对象的接口中, obj 是需要操作的 DOM 对象, speed 是动画速度,数值越小动画越快, mode 是动画方式,有 “zoom” , “slide” 两种方式,分别模拟 jQuery 中 hide() 和 slideUp() 的效果, fn 为回调函数。另外 hide() 中的 width 和 height 两个参数为 DOM 元素的宽度和高度,会在 DOM 元素对象中调用 hide() 时赋值。
1 // 动画对象模板 2 var Transform = function(obj, speed, mode, fn){ 3 this.obj = obj; 4 this.speed = speed; // 动画速度 5 this.mode = mode; // 动画形式 6 this.heightChange = 10; 7 this.fn = fn; 8 if( speed === 'fast') 9 this.speed = 10; 10 else if( speed === 'normal' ) 11 this.speed = 20; 12 else if( speed === 'slow' ) 13 this.speed = 30; 14 } 15 Transform.prototype = { 16 // 处理隐藏 17 hide: function( width, height ){ 18 var self = this; 19 if ( !this.speed ) { 20 this.obj.style.display = 'none'; 21 return; 22 } 23 width = width - this.widthChange > 0 ? width - this.widthChange : 0; 24 height = height - this.heightChange > 0 ? width - this.heightChange : 0; 25 // 26 if( width !== 0 || height !== 0 ) { 27 // 判断采用何种动画形式 28 if( this.mode === 'zoom' ) this.obj.style.width = width + 'px'; 29 this.obj.style.height = height + 'px'; 30 // 递归调用自身 31 setTimeout(function(){self.hide(width,height)},this.speed); 32 } else { 33 // 完成后清除所有 style 属性 34 this.obj.style.cssText = ""; 35 // 设置 display: none 36 this.obj.style.display = 'none'; 37 if(this.fn) this.fn.call(this.obj); 38 } 39 } 40 } 41
下面是创建一个 DOM 对象模板
-
1 // DOM 元素对象模板 2 var $ = function(id){ 3 this.id = id; 4 this.obj = document.getElementById(this.id); 5 } 6 $.prototype = { 7 // 获取元素的某项 CSS 8 getClass: function(name){ 9 // IE8及以下版本 10 if(this.obj.currentStyle) { 11 return this.obj.currentStyle[name]; 12 } 13 // Firefox, Chrome, IE9+ 14 else { 15 var style = document.defaultView.getComputedStyle(this.obj, null); 16 return style[name]; 17 } 18 }, 19 // 以元素高宽生成动画对象 20 cal: function(speed, mode, fn){ 21 // 创建动画对象 22 this.theTransform = new Transform(this.obj, speed, mode, fn); 23 this.theTransform.theWidth = this.getClass('width').replace('px',''); 24 this.theTransform.theHeight = this.getClass('height').replace('px',''); 25 // 按长宽比例计算单位时间内元素宽带减少值 26 this.theTransform.widthChange = this.theTransform.heightChange*(this.theTransform.theWidth / this.theTransform.theHeight); 27 }, 28 // 隐藏元素 29 hide: function(speed, mode, fn){ 30 this.cal(speed, mode, fn); 31 this.theTransform.hide(this.theTransform.theWidth, this.theTransform.theHeight); 32 }, 33 // 显示元素 34 show: function(speed, mode, fn){ 35 this.cal(speed, mode, fn); 36 this.theTransform.show(0, 0); 37 } 38 }
这里使用一个 getCss 方法获取 DOM 元素的宽和高,注意在不同的浏览器中获取方式是不同的,所以要作出判断(感受到 jQuery 的优势了吧),另外每次减少的宽度 widthChange 是按元素宽高比例算出的,不是直接指定的,这样是为了模拟 jQuery 中的动画效果。
需要使用这类动画而不需要加载 jQuery 库的童鞋可以下载完整 Demo ,连接 Demo 中的 js 文件到你的网页中就可以使用动画,比如网面中有一 id="box" 的 div ,那么可以使用以下这段 JavaScript 和 HTML 来隐藏和显示该 div 。
以需要操作的 DOM 元素的 id 实例化一个 DOM 元素对象
1 // 创建 DOM 元素对象 2 var theDom = new $('box');
相应的 HTML ,其中 'fast' 为动画速度,还可以选择 'normal', 'slow' ,代表三种不同速度,也可以直接填数值(建议 50 以内,数值越小动画速度越快),不填(即参数为'')则取消动画,直接隐藏或显示元素,'zoom' 为动画形式,还可以选择 'slide' ,还有一个选填的回调函数,如theDom.hide('fast', 'zoom', function(){alert('succeed');})。这些用法可以参考 Demo 。
1 <a href="#" onclick="theDom.hide('fast', 'zoom')">点击隐藏</a> 2 <a href="#" onclick="theDom.show('fast', 'zoom')">点击显示</a>
上例完整代码:
HTML部分:
1 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> 2 <html> 3 <head> 4 <title>About Kayo</title> 5 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> 6 <style type="text/css"> 7 <!-- 8 body {text-align: center; } 9 #box {width: 250px; height: 250px; margin: 0 auto; background: red; } 10 #box2 {width: 250px; height: 250px; margin: 0 auto; background: blue; } 11 a {display: block; width: 250px; height: 25px; margin: 3px auto; color: #000; } 12 --> 13 </style> 14 15 </head> 16 <body> 17 18 <div id="box"></div> 19 <a href="#" onclick="theDom.hide('fast', 'zoom')">点击隐藏</a> 20 <a href="#" onclick="theDom.show('fast', 'zoom')">点击显示</a> 21 <div id="box2"></div> 22 <a href="#" onclick="theDom2.hide('fast', 'slide')">点击隐藏</a> 23 <a href="#" onclick="theDom2.show('fast', 'slide')">点击显示</a> 24 <div id="footer"> 25 <script type="text/javascript" src="main.js"></script> 26 <script type="text/javascript"> 27 // 创建 DOM 元素对象 28 var theDom = new $('box'); 29 var theDom2 = new $('box2'); 30 </script> 31 </div> 32 33 </body> 34 </html>
JS部分:
1 // DOM 元素对象模板 2 var $ = function(id){ 3 this.id = id; 4 this.obj = document.getElementById(this.id); 5 } 6 $.prototype = { 7 // 获取元素的某项 CSS 8 getClass: function(name){ 9 // IE8及以下版本 10 if(this.obj.currentStyle) { 11 return this.obj.currentStyle[name]; 12 } 13 // Firefox, Chrome, IE9+ 14 else { 15 var style = document.defaultView.getComputedStyle(this.obj, null); 16 return style[name]; 17 } 18 }, 19 // 以元素高宽生成动画对象 20 cal: function(speed, mode, fn){ 21 // 创建动画对象 22 this.theTransform = new Transform(this.obj, speed, mode, fn); 23 this.theTransform.theWidth = this.getClass('width').replace('px',''); 24 this.theTransform.theHeight = this.getClass('height').replace('px',''); 25 // 按长宽比例计算单位时间内元素宽带减少值 26 this.theTransform.widthChange = this.theTransform.heightChange*(this.theTransform.theWidth / this.theTransform.theHeight); 27 }, 28 // 隐藏元素 29 hide: function(speed, mode, fn){ 30 this.cal(speed, mode, fn); 31 this.theTransform.hide(this.theTransform.theWidth, this.theTransform.theHeight); 32 }, 33 // 显示元素 34 show: function(speed, mode, fn){ 35 this.cal(speed, mode, fn); 36 this.theTransform.show(0, 0); 37 } 38 } 39 // 动画对象模板 40 var Transform = function(obj, speed, mode, fn){ 41 this.obj = obj; 42 this.speed = speed; // 动画速度 43 this.mode = mode; // 动画形式 44 this.heightChange = 10; 45 this.fn = fn; 46 if( speed === 'fast') 47 this.speed = 10; 48 else if( speed === 'normal' ) 49 this.speed = 20; 50 else if( speed === 'slow' ) 51 this.speed = 30; 52 } 53 Transform.prototype = { 54 // 处理隐藏 55 hide: function( width, height ){ 56 var self = this; 57 if ( !this.speed ) { 58 this.obj.style.display = 'none'; 59 return; 60 } 61 width = width - this.widthChange > 0 ? width - this.widthChange : 0; 62 height = height - this.heightChange > 0 ? width - this.heightChange : 0; 63 // 64 if( width !== 0 || height !== 0 ) { 65 // 判断采用何种动画形式 66 if( this.mode === 'zoom' ) this.obj.style.width = width + 'px'; 67 this.obj.style.height = height + 'px'; 68 // 递归调用自身 69 setTimeout(function(){self.hide(width,height)},this.speed); 70 } else { 71 // 完成后清除所有 style 属性 72 this.obj.style.cssText = ""; 73 // 设置 display: none 74 this.obj.style.display = 'none'; 75 if(this.fn) this.fn.call(this.obj); 76 } 77 }, 78 // 处理显示 79 show: function(width, height){ 80 // 判断元素是否为 block,若否,则设置为 block 81 if( this.obj.style.display !== 'block' ){ 82 // 判断采用何种动画形式 83 if( this.mode === 'zoom' ) this.obj.style.width = 0 + 'px'; 84 this.obj.style.height = 0 + 'px'; 85 this.obj.style.display = 'block'; 86 this.showIt( width, height ); 87 } 88 }, 89 showIt: function( width, height ){ 90 var self = this; 91 if ( !this.speed ) { 92 this.obj.style.display = 'block'; 93 return; 94 } 95 width = width + this.widthChange < this.theWidth ? width + this.widthChange : this.theWidth; 96 height = height + this.heightChange < this.theHeight ? height + this.heightChange : this.theHeight; 97 // 判断元素是否恢复到 CSS 中设定的高宽 98 if( width !== this.theWidth || height !== this.theHeight ) { 99 if( this.mode === 'zoom' ) this.obj.style.width = width + 'px'; 100 this.obj.style.height = height + 'px'; 101 setTimeout(function(){self.showIt(width,height)},this.speed); 102 } else { 103 // 完成后清除所有 style 属性 104 this.obj.style.cssText = ""; 105 // 设置 display: block 106 this.obj.style.display = 'block'; 107 if(this.fn) this.fn.call(this.obj); 108 } 109 } 110 }
来源: http://kayosite.com/achieve-jquery-animate-by-javascript.html