第十五节 JS面向对象实例及高级
作者:互联网
实例:面向对象的选项卡
把面向过程的程序,改写成面向对象的形式
原则:不能有函数套函数,但可以有全局变量
过程:
onload —— 改写成 构造函数,其中window.onload的功能是在页面加载时“初始换整个程序”,类似于构造函数——初始化整个对象
全局变量 —— 改写成 属性
函数 —— 改写成 方法
改错:this、时间、闭包、传参
对象与闭包:通过闭包传递this
1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <title>面向对象选项卡</title> 6 <style> 7 #div1 button{background: white;} 8 #div1 button.active{background: yellow;} 9 #div1 div{ 10 width: 200px; 11 height: 200px; 12 background: #cccccc; 13 display: none; 14 } 15 </style> 16 <script> 17 // window.onload = function () { 18 // var oDiv = document.getElementById('div1'); 19 // var aBtn = oDiv.getElementsByTagName('button'); 20 // var aDiv = oDiv.getElementsByTagName('div'); 21 // 22 // for (var i = 0; i < aBtn.length; i++) { 23 // aBtn[i].index = i; 24 // 25 // aBtn[i].onclick = function () { 26 // for (var i = 0; i < aBtn.length; i++) { 27 // aBtn[i].className = ''; 28 // aDiv[i].style.display = 'none'; 29 // }; 30 // this.className = 'active'; 31 // aDiv[this.index].style.display = 'block'; 32 // } 33 // } 34 // }; 35 36 // //此时我们要把上述语句改写为面向对象的代码 37 // var aBtn = null; //定义全局变量 38 // var aDiv = null; //定义全局变量 39 // 40 // window.onload = function () { 41 // var oDiv = document.getElementById('div1'); 42 // aBtn = oDiv.getElementsByTagName('button'); 43 // aDiv = oDiv.getElementsByTagName('div'); 44 // 45 // for (var i = 0; i < aBtn.length; i++) { 46 // aBtn[i].index = i; 47 // aBtn[i].onclick = fnClick; //函数没有嵌套,只是调用 48 // } 49 // }; 50 // 51 // function fnClick() { 52 // for (var i = 0; i < aBtn.length; i++) { 53 // aBtn[i].className = ''; 54 // aDiv[i].style.display = 'none'; 55 // } 56 // this.className = 'active'; //此处this表示当前被点击的那个按钮 57 // aDiv[this.index].style.display = 'block'; 58 // } 59 60 //在进行一次改写 61 window.onload = function () { 62 new TabSwitch('div1'); 63 }; 64 65 function TabSwitch(id) { 66 var _this = this; 67 68 var oDiv = document.getElementById(id); 69 70 this.aBtn = oDiv.getElementsByTagName('button'); 71 this.aDiv = oDiv.getElementsByTagName('div'); 72 73 for (var i = 0; i < this.aBtn.length; i++) { 74 this.aBtn[i].index = i; 75 // this.aBtn[i].onclick = this.fnClick; //此时fnClick已经不是一个函数了,而是一个方法 76 this.aBtn[i].onclick = function () { 77 _this.fnClick(this); 78 }; 79 80 } 81 } 82 83 TabSwitch.prototype.fnClick = function (oBtn) { 84 // alert(this); //[object HTMLButtonElement] 85 86 for (var i = 0; i < this.aBtn.length; i++) { 87 this.aBtn[i].className = ''; 88 this.aDiv[i].style.display = 'none'; 89 } 90 oBtn.className = 'active'; //此时this代表当前的对象 91 this.aDiv[oBtn.index].style.display = 'block'; 92 }; 93 </script> 94 </head> 95 <body> 96 <div id="div1"> 97 <button class="active">aaa</button> 98 <button>bbb</button> 99 <button>ccc</button> 100 <div style="display: block">111</div> 101 <div>222</div> 102 <div>333</div> 103 </div> 104 </body> 105 </html>View Code
Json方式的面向对象
把方法包在一个Json里
<script> // var json = { // a:12, // b:5, // c:'abc', // d:function () {alert('a');} // }; // alert(json.a); //12 // json.d(); //a // var json = { // a:12, // show:function () {alert(this);} //此时this即指json // }; // json.show(); //[object Object] //改写67.html,较67.html更加简单,但是缺点是不适合多个对象,比如再创建一个其他用户时,又需要在创建一个Json对象 var json = { name:'haha', qq:'123456789', showName:function (){ alert('他的名字叫做:'+this.name); }, showQQ:function () { alert('他的QQ号为:'+this.qq); } }; json.showName(); json.showQQ(); </script>View Code
有人称作——命名空间
<script> var json = {}; //json中包含另外3个json json.common = {}; json.fx = {}; json.site = {}; //在不同的json里面写同一个名字的函数,并且不会相互冲突 json.common.getUser = function () { alert('a'); }; json.fx.getUser = function () { alert('b'); }; json.site.getUser = function () { alert('c'); }; json.common.getUser(); json.fx.getUser(); json.site.getUser(); </script>View Code
在公司里,把同一类方法,包在一起,既不会相互冲突,又方便查找
引用 :用“=”处理,和复制相似,但是两者指向的是同一个事物,而不是两个
1 <script> 2 // var arr1 = [1,2,3]; 3 // var arr2 = arr1; 4 // 5 // arr2.push(4); 6 // 7 // alert(arr2); //返回:1,2,3,4 8 // alert(arr1); //返回:1,2,3,4 9 //原因是上面“arr2 = arr1;”语句知识把两个变量都指向了同一个数组,并不是指向两个不同的数组,此时该语句叫做“引用”,若想使其不相同,如下: 10 var arr1 = [1,2,3]; 11 var arr2 = []; 12 13 for (var i = 0; i<arr1.length; i++){ 14 arr2.push(arr1[i]); 15 } 16 arr2.push(4); 17 18 alert(arr2); //返回:1,2,3,4 19 alert(arr1); //返回:1,2,3 20 </script>View Code
对象的继承
什么是继承:在原有的基础上,略作修改,得到一个新的类,并且不影响原有类的功能
1 <script> 2 function A() { //A的属性都写在函数内,构造函数 3 this.abc = 12; 4 } 5 6 A.prototype.show = function () { //A的方法都现在原型上 7 alert(this.abc); 8 }; 9 10 function B() { 11 A.call(this); //此时this表示new B() 即新建的B对象 用call来继承父级的属性 12 } 13 14 // //继承属性 15 // var obj = new B(); 16 // alert(obj.abc); //返回12 当B方法内没有定义“A.call(this);”时,返回的是undefined 17 18 // //继承父级的属性我们可以用call,但是继承父级的方法我们用什么呢?如下: 19 // B.prototype = A.prototype; 20 // var obj = new B(); 21 // obj.show(); //返回12 22 23 //但是问题在于当B存在自己的方法的时候时,如: 24 B.prototype = A.prototype; 25 26 B.prototype.fn = function () { 27 alert('abc'); 28 }; 29 30 var objB = new B(); 31 var objA = new B(); 32 33 objA.fn(); //返回 abc 按理说不应该弹出该结果,因为B继承A;但是这样一来A B就互相继承了 34 </script>View Code
拖拽和继承
面向对象的拖拽——改写原有拖拽
1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <title>面向对象的拖拽</title> 6 <style> 7 #div1{ 8 width: 200px; 9 height: 200px; 10 background: red; 11 position: absolute; 12 } 13 </style> 14 <script> 15 // //面向过程的拖拽: 16 // window.onload = function () { 17 // var oDiv = document.getElementById('div1'); 18 // 19 // oDiv.onmousedown = function (ev) { 20 // var oEvent = ev||event; 21 // 22 // var disX = oEvent.clientX-oDiv.offsetLeft; 23 // var disY = oEvent.clientY-oDiv.offsetTop; 24 // 25 // document.onmousemove = function (ev) { 26 // var oEvent = ev||event; 27 // 28 // oDiv.style.left = oEvent.clientX-disX+'px'; 29 // oDiv.style.top = oEvent.clientY-disY+'px'; 30 // }; 31 // document.onmouseup = function () { 32 // document.onmousemove = null; 33 // document.onmouseup = null; 34 // }; 35 // }; 36 // }; 37 38 //面向对象的拖拽: 39 //第一步:把所有的函数嵌套去掉 40 //第二步:把所有在多个函数中用到的变量,改为全局变量 41 // // var oDiv = null; 42 // var disX = 0; 43 // var disY = 0; 44 // 45 // function Drag(id) { 46 // oDiv = document.getElementById(id); 47 // oDiv.onmousedown = this.fnDown; 48 // }; 49 // 50 // function fnDown(ev) { 51 // var oEvent = ev||event; 52 // 53 // disX = oEvent.clientX-oDiv.offsetLeft; 54 // disY = oEvent.clientY-oDiv.offsetTop; 55 // 56 // document.onmousemove = fnMove; 57 // document.onmouseup = fnUp; 58 // } 59 // function fnMove(ev) { 60 // var oEvent = ev||event; 61 // 62 // oDiv.style.left = oEvent.clientX-disX+'px'; 63 // oDiv.style.top = oEvent.clientY-disY+'px'; 64 // } 65 // function fnUp() { 66 // document.onmousemove = null; 67 // document.onmouseup = null; 68 // } 69 70 //第三步:把“var oDiv = null;”注释掉,把对象的属性用this表示,即把div当做属性,然后合理添加this 71 // var oDiv = null; 72 window.onload = function () { 73 new Drag('div1'); 74 }; 75 76 function Drag(id) { 77 var _this = this; 78 79 this.disX = 0; 80 this.disY = 0; 81 82 this.oDiv = document.getElementById(id); 83 this.oDiv.onmousedown = function (ev) { 84 _this.fnDown(ev); 85 }; 86 }; 87 88 Drag.prototype.fnDown = function (ev) { 89 var _this = this; 90 91 var oEvent = ev||event; 92 93 this.disX = oEvent.clientX-this.oDiv.offsetLeft; 94 this.disY = oEvent.clientY-this.oDiv.offsetTop; 95 96 document.onmousemove = function (ev) { 97 _this.fnMove(ev); 98 }; 99 document.onmouseup = function (ev) { 100 _this.fnUp(ev); 101 }; 102 }; 103 Drag.prototype.fnMove = function (ev) { 104 var oEvent = ev||event; 105 106 this.oDiv.style.left = oEvent.clientX-this.disX+'px'; 107 this.oDiv.style.top = oEvent.clientY-this.disY+'px'; 108 }; 109 Drag.prototype.fnUp = function () { 110 document.onmousemove = null; 111 document.onmouseup = null; 112 }; 113 114 //此时我们就可以把这些拖拽操作的方法,提取出来放到一个js文件中,方便之后需要使用只需 src引入 来使用即可 115 </script> 116 </head> 117 <body> 118 <div id="div1"></div> 119 </body> 120 </html>View Code
instanceof运算符:查看对象是否是某个类的实例
使用继承
限制范围的拖拽类
1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <title>面向对象的拖拽</title> 6 <style> 7 #div1{ 8 width: 200px; 9 height: 200px; 10 background: red; 11 position: absolute; 12 } 13 #div2{ 14 width: 200px; 15 height: 200px; 16 background: green; 17 position: absolute; 18 } 19 </style> 20 <script src="74Drag.js"></script> 21 <script src="74limitDrag.js"></script> 22 <script> 23 window.onload = function () { 24 new Drag('div1'); 25 new LimitDrag('div2'); 26 }; 27 </script> 28 </head> 29 <body> 30 <div id="div1">普通拖拽</div> 31 <div id="div2">范围受限制的拖拽</div> 32 </body> 33 </html>View Code
1 function Drag(id) { 2 var _this = this; 3 4 this.disX = 0; 5 this.disY = 0; 6 7 this.oDiv = document.getElementById(id); 8 this.oDiv.onmousedown = function (ev) { 9 _this.fnDown(ev); 10 11 return false; //拖拽一个物体时,防止另一个物体中的文字被选中 12 }; 13 }; 14 15 Drag.prototype.fnDown = function (ev) { 16 var _this = this; 17 18 var oEvent = ev||event; 19 20 this.disX = oEvent.clientX-this.oDiv.offsetLeft; 21 this.disY = oEvent.clientY-this.oDiv.offsetTop; 22 23 document.onmousemove = function (ev) { 24 _this.fnMove(ev); 25 }; 26 document.onmouseup = function (ev) { 27 _this.fnUp(ev); 28 }; 29 }; 30 Drag.prototype.fnMove = function (ev) { 31 var oEvent = ev||event; 32 33 this.oDiv.style.left = oEvent.clientX-this.disX+'px'; 34 this.oDiv.style.top = oEvent.clientY-this.disY+'px'; 35 }; 36 Drag.prototype.fnUp = function () { 37 document.onmousemove = null; 38 document.onmouseup = null; 39 };74Drag.js
1 // 面向对象的继承 2 function LimitDrag(id) { 3 Drag.call(this, id); //继承属性 4 } 5 6 for (var i in Drag.prototype) { 7 LimitDrag.prototype[i] = Drag.prototype[i]; 8 } 9 10 //覆盖掉其父级“Drag”的fnMove方法,并重写该方法 11 LimitDrag.prototype.fnMove = function (ev) { 12 var oEvent = ev||event; 13 14 //重新写继承的父级方法 15 var l = oEvent.clientX-this.disX; 16 var t = oEvent.clientY-this.disY; 17 18 if (l < 0) { //重新父级方法,使拖拽左右不可拖出可视区 19 l = 0; 20 } else if (l>document.documentElement.clientWidth-this.oDiv.offsetWidth) { 21 l = document.documentElement.clientWidth-this.oDiv.offsetWidth; 22 } 23 24 this.oDiv.style.left = l+'px'; 25 this.oDiv.style.top = t+'px'; 26 };74limitDrag.js
继承的好处体现在,我把父级的方法继承过来,也可以根据自己需要重写所继承父级方法中不存在的东西
构造函数伪装
属性的继承
原理:欺骗构造函数
call的使用
1 <script> 2 function show(a, b) { 3 alert('this是:'+this+'\na是:'+a+'\nb是:'+b); 4 } 5 6 // show(12,5); //返回:this是:[object Window] a是:12 b是:5 7 // show.call(12, 5); //返回:this是:12 a是:5 b是:undefined 此时第一个参数即为this 8 show.call('haha', 12, 5); //this是:haha a是:12 b是:5 9 </script>View Code
不使用“引用”的原型继承
1 <script> 2 function A() { //A的属性都写在函数内,构造函数 3 this.abc = 12; 4 } 5 6 A.prototype.show = function () { //A的方法都现在原型上 7 alert(this.abc); 8 }; 9 10 function B() { 11 A.call(this); //此时this表示new B() 即新建的B对象 用call来继承父级的属性 12 } 13 14 // //继承属性 15 // var obj = new B(); 16 // alert(obj.abc); //返回12 当B方法内没有定义“A.call(this);”时,返回的是undefined 17 18 // //继承父级的属性我们可以用call,但是继承父级的方法我们用什么呢?如下: 19 // B.prototype = A.prototype; 20 // var obj = new B(); 21 // obj.show(); //返回12 22 23 24 // //但是问题在于当B存在自己的方法的时候时,如: 25 // B.prototype = A.prototype; 26 // 27 // B.prototype.fn = function () { 28 // alert('abc'); 29 // }; 30 // 31 // var objB = new B(); 32 // var objA = new B(); 33 // 34 // objA.fn(); //返回 abc 按理说不应该弹出该结果,因为B继承A;但是这样一来A B就互相继承了, 35 36 // 其实上述也是“引用”惹的祸,解决办法如下:复制,让他们指向不同的物体 37 for (var i in A.prototype) { 38 B.prototype[i] = A.prototype[i]; 39 } 40 B.prototype.fn = function () { 41 alert('abc'); 42 }; 43 44 var objB = new B(); 45 var objA = new B(); 46 47 objA.fn(); 48 </script>View Code
原型链
方法的继承
原理:复制方法
覆盖原型和方法复制
系统对象
本地对象(非静态对象)
什么是本地对象:简单来说,需要进行实例化才能使用系统自带的类,叫做本地对象,常用非静态对象:Object、Function、Array、String、Boolean、Number、Date、RegExp(正则)、Error
内置对象(静态对象)
什么是本地对象:简单来说,凡是不需要new就能使用的对象就是内置对象,如Global(虚假对象,因为基本上用不到)、Math
1 var obj = new Math(); //错误用法,因为它属于静态对象 2 Math.ceil(); //正确使用方法
前两个对象不依赖于JS的执行环境,可以说是JS本身的对象
宿主对象(JS的运行环境)
由浏览器提供的对象,其实就是DOM、BOM;
NodeJS运行环境是后台,所以其宿主对象就是后台的一系列对象。
标签:function,oEvent,ev,oDiv,var,面向对象,第十五,prototype,JS 来源: https://www.cnblogs.com/han-bky/p/10412299.html