第十五节 JS面向对象实例及高级
实例:面向对象的选项卡
把面向过程的程序,改写成面向对象的形式
原则:不能有函数套函数,但可以有全局变量
过程:
onload —— 改写成 构造函数,其中window.onload的功能是在页面加载时“初始换整个程序”,类似于构造函数——初始化整个对象
全局变量 —— 改写成 属性
函数 —— 改写成 方法
改错:this、时间、闭包、传参
对象与闭包:通过闭包传递this
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>面向对象选项卡</title>
<style>
#div1 button{background: white;}
#div1 button.active{background: yellow;}
#div1 div{
width: 200px;
height: 200px;
background: #cccccc;
display: none;
}
</style>
<script>
// window.onload = function () {
// var oDiv = document.getElementById('div1');
// var aBtn = oDiv.getElementsByTagName('button');
// var aDiv = oDiv.getElementsByTagName('div');
//
// for (var i = 0; i < aBtn.length; i++) {
// aBtn[i].index = i;
//
// aBtn[i].onclick = function () {
// for (var i = 0; i < aBtn.length; i++) {
// aBtn[i].className = '';
// aDiv[i].style.display = 'none';
// };
// this.className = 'active';
// aDiv[this.index].style.display = 'block';
// }
// }
// }; // //此时我们要把上述语句改写为面向对象的代码
// var aBtn = null; //定义全局变量
// var aDiv = null; //定义全局变量
//
// window.onload = function () {
// var oDiv = document.getElementById('div1');
// aBtn = oDiv.getElementsByTagName('button');
// aDiv = oDiv.getElementsByTagName('div');
//
// for (var i = 0; i < aBtn.length; i++) {
// aBtn[i].index = i;
// aBtn[i].onclick = fnClick; //函数没有嵌套,只是调用
// }
// };
//
// function fnClick() {
// for (var i = 0; i < aBtn.length; i++) {
// aBtn[i].className = '';
// aDiv[i].style.display = 'none';
// }
// this.className = 'active'; //此处this表示当前被点击的那个按钮
// aDiv[this.index].style.display = 'block';
// } //在进行一次改写
window.onload = function () {
new TabSwitch('div1');
}; function TabSwitch(id) {
var _this = this; var oDiv = document.getElementById(id); this.aBtn = oDiv.getElementsByTagName('button');
this.aDiv = oDiv.getElementsByTagName('div'); for (var i = 0; i < this.aBtn.length; i++) {
this.aBtn[i].index = i;
// this.aBtn[i].onclick = this.fnClick; //此时fnClick已经不是一个函数了,而是一个方法
this.aBtn[i].onclick = function () {
_this.fnClick(this);
}; }
} TabSwitch.prototype.fnClick = function (oBtn) {
// alert(this); //[object HTMLButtonElement] for (var i = 0; i < this.aBtn.length; i++) {
this.aBtn[i].className = '';
this.aDiv[i].style.display = 'none';
}
oBtn.className = 'active'; //此时this代表当前的对象
this.aDiv[oBtn.index].style.display = 'block';
};
</script>
</head>
<body>
<div id="div1">
<button class="active">aaa</button>
<button>bbb</button>
<button>ccc</button>
<div style="display: block">111</div>
<div>222</div>
<div>333</div>
</div>
</body>
</html>
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>
有人称作——命名空间
<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>
在公司里,把同一类方法,包在一起,既不会相互冲突,又方便查找
引用 :用“=”处理,和复制相似,但是两者指向的是同一个事物,而不是两个
<script>
// var arr1 = [1,2,3];
// var arr2 = arr1;
//
// arr2.push(4);
//
// alert(arr2); //返回:1,2,3,4
// alert(arr1); //返回:1,2,3,4
//原因是上面“arr2 = arr1;”语句知识把两个变量都指向了同一个数组,并不是指向两个不同的数组,此时该语句叫做“引用”,若想使其不相同,如下:
var arr1 = [1,2,3];
var arr2 = []; for (var i = 0; i<arr1.length; i++){
arr2.push(arr1[i]);
}
arr2.push(4); alert(arr2); //返回:1,2,3,4
alert(arr1); //返回:1,2,3
</script>
对象的继承
什么是继承:在原有的基础上,略作修改,得到一个新的类,并且不影响原有类的功能
<script>
function A() { //A的属性都写在函数内,构造函数
this.abc = 12;
} A.prototype.show = function () { //A的方法都现在原型上
alert(this.abc);
}; function B() {
A.call(this); //此时this表示new B() 即新建的B对象 用call来继承父级的属性
} // //继承属性
// var obj = new B();
// alert(obj.abc); //返回12 当B方法内没有定义“A.call(this);”时,返回的是undefined // //继承父级的属性我们可以用call,但是继承父级的方法我们用什么呢?如下:
// B.prototype = A.prototype;
// var obj = new B();
// obj.show(); //返回12 //但是问题在于当B存在自己的方法的时候时,如:
B.prototype = A.prototype; B.prototype.fn = function () {
alert('abc');
}; var objB = new B();
var objA = new B(); objA.fn(); //返回 abc 按理说不应该弹出该结果,因为B继承A;但是这样一来A B就互相继承了
</script>
拖拽和继承
面向对象的拖拽——改写原有拖拽
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>面向对象的拖拽</title>
<style>
#div1{
width: 200px;
height: 200px;
background: red;
position: absolute;
}
</style>
<script>
// //面向过程的拖拽:
// window.onload = function () {
// var oDiv = document.getElementById('div1');
//
// oDiv.onmousedown = function (ev) {
// var oEvent = ev||event;
//
// var disX = oEvent.clientX-oDiv.offsetLeft;
// var disY = oEvent.clientY-oDiv.offsetTop;
//
// document.onmousemove = function (ev) {
// var oEvent = ev||event;
//
// oDiv.style.left = oEvent.clientX-disX+'px';
// oDiv.style.top = oEvent.clientY-disY+'px';
// };
// document.onmouseup = function () {
// document.onmousemove = null;
// document.onmouseup = null;
// };
// };
// }; //面向对象的拖拽:
//第一步:把所有的函数嵌套去掉
//第二步:把所有在多个函数中用到的变量,改为全局变量
// // var oDiv = null;
// var disX = 0;
// var disY = 0;
//
// function Drag(id) {
// oDiv = document.getElementById(id);
// oDiv.onmousedown = this.fnDown;
// };
//
// function fnDown(ev) {
// var oEvent = ev||event;
//
// disX = oEvent.clientX-oDiv.offsetLeft;
// disY = oEvent.clientY-oDiv.offsetTop;
//
// document.onmousemove = fnMove;
// document.onmouseup = fnUp;
// }
// function fnMove(ev) {
// var oEvent = ev||event;
//
// oDiv.style.left = oEvent.clientX-disX+'px';
// oDiv.style.top = oEvent.clientY-disY+'px';
// }
// function fnUp() {
// document.onmousemove = null;
// document.onmouseup = null;
// } //第三步:把“var oDiv = null;”注释掉,把对象的属性用this表示,即把div当做属性,然后合理添加this
// var oDiv = null;
window.onload = function () {
new Drag('div1');
}; function Drag(id) {
var _this = this; this.disX = 0;
this.disY = 0; this.oDiv = document.getElementById(id);
this.oDiv.onmousedown = function (ev) {
_this.fnDown(ev);
};
}; Drag.prototype.fnDown = function (ev) {
var _this = this; var oEvent = ev||event; this.disX = oEvent.clientX-this.oDiv.offsetLeft;
this.disY = oEvent.clientY-this.oDiv.offsetTop; document.onmousemove = function (ev) {
_this.fnMove(ev);
};
document.onmouseup = function (ev) {
_this.fnUp(ev);
};
};
Drag.prototype.fnMove = function (ev) {
var oEvent = ev||event; this.oDiv.style.left = oEvent.clientX-this.disX+'px';
this.oDiv.style.top = oEvent.clientY-this.disY+'px';
};
Drag.prototype.fnUp = function () {
document.onmousemove = null;
document.onmouseup = null;
}; //此时我们就可以把这些拖拽操作的方法,提取出来放到一个js文件中,方便之后需要使用只需 src引入 来使用即可
</script>
</head>
<body>
<div id="div1"></div>
</body>
</html>
instanceof运算符:查看对象是否是某个类的实例
使用继承
限制范围的拖拽类
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>面向对象的拖拽</title>
<style>
#div1{
width: 200px;
height: 200px;
background: red;
position: absolute;
}
#div2{
width: 200px;
height: 200px;
background: green;
position: absolute;
}
</style>
<script src="74Drag.js"></script>
<script src="74limitDrag.js"></script>
<script>
window.onload = function () {
new Drag('div1');
new LimitDrag('div2');
};
</script>
</head>
<body>
<div id="div1">普通拖拽</div>
<div id="div2">范围受限制的拖拽</div>
</body>
</html>
function Drag(id) {
var _this = this; this.disX = 0;
this.disY = 0; this.oDiv = document.getElementById(id);
this.oDiv.onmousedown = function (ev) {
_this.fnDown(ev); return false; //拖拽一个物体时,防止另一个物体中的文字被选中
};
}; Drag.prototype.fnDown = function (ev) {
var _this = this; var oEvent = ev||event; this.disX = oEvent.clientX-this.oDiv.offsetLeft;
this.disY = oEvent.clientY-this.oDiv.offsetTop; document.onmousemove = function (ev) {
_this.fnMove(ev);
};
document.onmouseup = function (ev) {
_this.fnUp(ev);
};
};
Drag.prototype.fnMove = function (ev) {
var oEvent = ev||event; this.oDiv.style.left = oEvent.clientX-this.disX+'px';
this.oDiv.style.top = oEvent.clientY-this.disY+'px';
};
Drag.prototype.fnUp = function () {
document.onmousemove = null;
document.onmouseup = null;
};
74Drag.js
// 面向对象的继承
function LimitDrag(id) {
Drag.call(this, id); //继承属性
} for (var i in Drag.prototype) {
LimitDrag.prototype[i] = Drag.prototype[i];
} //覆盖掉其父级“Drag”的fnMove方法,并重写该方法
LimitDrag.prototype.fnMove = function (ev) {
var oEvent = ev||event; //重新写继承的父级方法
var l = oEvent.clientX-this.disX;
var t = oEvent.clientY-this.disY; if (l < 0) { //重新父级方法,使拖拽左右不可拖出可视区
l = 0;
} else if (l>document.documentElement.clientWidth-this.oDiv.offsetWidth) {
l = document.documentElement.clientWidth-this.oDiv.offsetWidth;
} this.oDiv.style.left = l+'px';
this.oDiv.style.top = t+'px';
};
74limitDrag.js
继承的好处体现在,我把父级的方法继承过来,也可以根据自己需要重写所继承父级方法中不存在的东西
构造函数伪装
属性的继承
原理:欺骗构造函数
call的使用
<script>
function show(a, b) {
alert('this是:'+this+'\na是:'+a+'\nb是:'+b);
} // show(12,5); //返回:this是:[object Window] a是:12 b是:5
// show.call(12, 5); //返回:this是:12 a是:5 b是:undefined 此时第一个参数即为this
show.call('haha', 12, 5); //this是:haha a是:12 b是:5
</script>
不使用“引用”的原型继承
<script>
function A() { //A的属性都写在函数内,构造函数
this.abc = 12;
} A.prototype.show = function () { //A的方法都现在原型上
alert(this.abc);
}; function B() {
A.call(this); //此时this表示new B() 即新建的B对象 用call来继承父级的属性
} // //继承属性
// var obj = new B();
// alert(obj.abc); //返回12 当B方法内没有定义“A.call(this);”时,返回的是undefined // //继承父级的属性我们可以用call,但是继承父级的方法我们用什么呢?如下:
// B.prototype = A.prototype;
// var obj = new B();
// obj.show(); //返回12 // //但是问题在于当B存在自己的方法的时候时,如:
// B.prototype = A.prototype;
//
// B.prototype.fn = function () {
// alert('abc');
// };
//
// var objB = new B();
// var objA = new B();
//
// objA.fn(); //返回 abc 按理说不应该弹出该结果,因为B继承A;但是这样一来A B就互相继承了, // 其实上述也是“引用”惹的祸,解决办法如下:复制,让他们指向不同的物体
for (var i in A.prototype) {
B.prototype[i] = A.prototype[i];
}
B.prototype.fn = function () {
alert('abc');
}; var objB = new B();
var objA = new B(); objA.fn();
</script>
原型链
方法的继承
原理:复制方法
覆盖原型和方法复制
系统对象
本地对象(非静态对象)
什么是本地对象:简单来说,需要进行实例化才能使用系统自带的类,叫做本地对象,常用非静态对象:Object、Function、Array、String、Boolean、Number、Date、RegExp(正则)、Error
内置对象(静态对象)
什么是本地对象:简单来说,凡是不需要new就能使用的对象就是内置对象,如Global(虚假对象,因为基本上用不到)、Math
var obj = new Math(); //错误用法,因为它属于静态对象
Math.ceil(); //正确使用方法
前两个对象不依赖于JS的执行环境,可以说是JS本身的对象
宿主对象(JS的运行环境)
由浏览器提供的对象,其实就是DOM、BOM;
Node.js运行环境是后台,所以其宿主对象就是后台的一系列对象。
第十五节 JS面向对象实例及高级的更多相关文章
- 第十四节 JS面向对象基础
什么是面向对象:在不需要知道它内部结构和原理的情况下,能够有效的使用它,比如,电视.洗衣机等也可以被定义为对象 什么是对象:在Java中对象就是“类的实体化”,在JavaScript中基本相同:对象是 ...
- Ext JS学习第十六天 事件机制event(一) DotNet进阶系列(持续更新) 第一节:.Net版基于WebSocket的聊天室样例 第十五节:深入理解async和await的作用及各种适用场景和用法 第十五节:深入理解async和await的作用及各种适用场景和用法 前端自动化准备和详细配置(NVM、NPM/CNPM、NodeJs、NRM、WebPack、Gulp/Grunt、G
code&monkey Ext JS学习第十六天 事件机制event(一) 此文用来记录学习笔记: 休息了好几天,从今天开始继续保持更新,鞭策自己学习 今天我们来说一说什么是事件,对于事件 ...
- 第四百一十五节,python常用排序算法学习
第四百一十五节,python常用排序算法学习 常用排序 名称 复杂度 说明 备注 冒泡排序Bubble Sort O(N*N) 将待排序的元素看作是竖着排列的“气泡”,较小的元素比较轻,从而要往上浮 ...
- 第三百八十五节,Django+Xadmin打造上线标准的在线教育平台—登录功能实现,回填数据以及错误提示html
第三百八十五节,Django+Xadmin打造上线标准的在线教育平台—登录功能实现 1,配置登录路由 from django.conf.urls import url, include # 导入dja ...
- 第三百一十五节,Django框架,CSRF跨站请求伪造
第三百一十五节,Django框架,CSRF跨站请求伪造 全局CSRF 如果要启用防止CSRF跨站请求伪造,就需要在中间件开启CSRF #中间件 MIDDLEWARE = [ 'django.midd ...
- centos shell脚本编程1 正则 shell脚本结构 read命令 date命令的用法 shell中的逻辑判断 if 判断文件、目录属性 shell数组简单用法 $( ) 和${ } 和$(( )) 与 sh -n sh -x sh -v 第三十五节课
centos shell脚本编程1 正则 shell脚本结构 read命令 date命令的用法 shell中的逻辑判断 if 判断文件.目录属性 shell数组简单用法 $( ) 和$ ...
- centos lamp/lnmp阶段复习 以后搬迁discuz论坛不需要重新安装,只需修改配置文件即可 安装wordpress 安装phpmyadmin 定时备份mysql两种方法 第二十五节课
centos lamp/lnmp阶段复习 以后搬迁discuz论坛不需要重新安装,只需修改配置文件即可 安装wordpress 安装phpmyadmin 定时备份mysql两种方法 第二十五节 ...
- centos Linux系统日常管理2 tcpdump,tshark,selinux,strings命令, iptables ,crontab,TCP,UDP,ICMP,FTP网络知识 第十五节课
centos Linux系统日常管理2 tcpdump,tshark,selinux,strings命令, iptables ,crontab,TCP,UDP,ICMP,FTP网络知识 第十五节课 ...
- 风炫安全WEB安全学习第二十五节课 利用XSS键盘记录
风炫安全WEB安全学习第二十五节课 利用XSS键盘记录 XSS键盘记录 同源策略是浏览器的一个安全功能,不同源的客户端脚本在没有明确授权的情况下,不能读写对方资源.所以xyz.com下的js脚本采用a ...
随机推荐
- Apache Flink系列(1)-概述
一.设计思想及介绍 基本思想:“一切数据都是流,批是流的特例” 1.Micro Batching 模式 在Micro-Batching模式的架构实现上就有一个自然流数据流入系统进行攒批的过程,这在一定 ...
- 问题:CGI返回给前端的汉字数据是乱码(已解决)
今天,我在写CGI程序,把后台数据返回到前台页面上,出现乱码, 不好看,所以,我在Content-type:application后面加了字符集的设置(字符集和前端一样), fprintf(stdou ...
- html中的列表
无序列表(什么前面默认一个实心的黑原点) <ul> <li>什么</li> <li>什么</li> <li>什么</li& ...
- java课程设计团队博客《基于学院的搜索引擎》
JAVA课程设计 基于学院网站的搜索引擎 对学院网站用爬虫进行抓取.建索(需要中文分词).排序(可选).搜索.数据摘要高亮.分页显示.Web界面. 一.团队介绍 学号 班级 姓名 简介 2016211 ...
- 对于EMC DAE、DPE、SPE、SPS的解释
对于EMC DAE.DPE.SPE.SPS的解释: DAE: Disk Array Enclosure 单一的磁盘扩展单元 CX200/CX300/CX400/CX500CX600/CX700 DPE ...
- 人工智能--AI篇
AI背景 在当今互联网信息高速发展的大背景下,人工智能(AI)已经开始走进了千家万户,逐渐和我们的生活接轨,那具体什么是AI呢? 什么是人工智能(AI)? 人工智能:简单理解就是由人制造出来的,有一定 ...
- LeetCode 96 - 不同的二叉搜索树 - [DP]
假定 $f[n]$ 表示有 $n$ 个节点的二叉树,有多少种不同结构. 因此 $f[n] = \sum_{i=0}^{n-1} (f[i] \times f[n-1-i])$,选一个节点作为根节点,那 ...
- yii2安装与初始化
yii2安装与初始化-Yii2学习笔记(一) 一.安装项目: 使用composer下载安装yii2 advanced安装包: composer create-project yiisoft/yii ...
- 输入URL地址到页面加载完成 过程
在浏览器的地址栏中输入URL地址"http://www.gacl.cn:8080/JavaWebDemo1/1.jsp"去访问服务器上的1.jsp这个web资源的过程 1.浏览器根 ...
- 滴滴出行基于RocketMQ构建企业级消息队列服务的实践
小结: 1. https://mp.weixin.qq.com/s/v6NM3UgX-qTI7yO1QPCJrw 滴滴出行基于RocketMQ构建企业级消息队列服务的实践 原创: 江海挺 阿里巴巴中间 ...