第十五节 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+'
a是:'+a+'
b是:'+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;

    Node.js运行环境是后台,所以其宿主对象就是后台的一系列对象。

原文地址:https://www.cnblogs.com/han-bky/p/10412299.html