JS面向对象:
JS面向对象基础:
1.什么是面向对象:即在不了解某个对象内部原理的情况下,我们就可以直接使用它的功能
使用面向对象时,我们只关注对象提供的功能,不关注内部的细节
面向对象是一种通用思想,并非只是在编程中才能使用
2.面向对象编程(OOP)的特点:
--抽象:抓住核心问题,把与问题相关的特征抽出来,放到系统里面
--封装:不考虑内部实现,只考虑使用功能
--继承:从父类对象上继承一些方法/属性,子类又有字节的一些新的属性(分为多重继承,多态)
3.对象的组成:
1)--属性:与变量是等价的,平常我们定义的变量的特点:自由的不属于任何一个对象,
而当一个变量属于某个对象时,我们就叫这个变量为属性.
var a=12; //变量:自由的,不属于任何一个事物
alert(a);
var arr=[1,2,3,4];
arr.a=12; //属性:不自由,是属于一个对象的变量
alert(arr.a);
2)--方法:与函数是等价的,平常所写的函数的特点:是自由的,
而当一个函数属于某个对象时我们就叫这个函数为方法
function aaa(){ //函数:自由的
alert('abc');
}
var arr=[1,2,3,4];
arr.aaa=function(){ //方法:属于一个对象的函数
alert('abc');
}
aaa();
arr.aaa();
4.面向对象中的this:指当前的方法属于哪个对象,this就指的是那个对象
(之前我们为对象添加一个事件,即为对象添加一个方法)
5.面向对象中的window:当我们定义一个全局的方法/函数时,它是属于window之下的一个方法
function show(){ //全局的函数/方法,属于window
alert(this); //弹出[object window]
}
==>等价于:
window.show=function(){
alert(this); //弹出[object window]
}
6.注意的问题:我们不能在系统对象(如Array,Date等)中随意添加属性,方法,否则会覆盖已有方法和属性
我们经常用object对象来添加属性/方法,因为其几乎没有自己的属性和方法,可防止与添加的产生冲突
7.自定义第一个面向对象的小程序:
var obj=new Object();
obj.name='yufan';
obj.myQQ='123456';
obj.show=function(){
alert('我的姓名:'+this.name);
alert('我的QQ:'+this.myQQ);
}
obj.show(); //调用
当有多个用户时,以上方法就会有大量重复的代码,所以我们需要封装成一个函数
function addPerson(name,qq){
//原料
var obj=new Object();
//加工
obj.name=name;
obj.myQQ=qq;
obj.show=function(){
alert('我的姓名:'+this.name);
alert('我的QQ:'+this.myQQ);
}
//出厂
return obj;
}
var obj1=addPerson('yufan','123456'); //创建对象
var obj2=addPerson('red','456789'); //再次创建对象
obj1.show(); //调用对象上面的方法
obj2.show();
alert(obj1.show==obj2.show); //false
注**上面的概念理解:
--上面的addPerson函数叫做:构造函数(和普通的函数没有区别,只不过他的作用不同而已)
--上面构造函数创建过程的方式叫做工厂方式(有原料,有加工,有出厂)
--工厂方式有缺点:
--没有new
解决:当一个全局函数在调用时,前面加上new,则表示系统自己定义一个新对象
--实例化对象时,每一个对象都有一个自己的方法,而这些对象的方法明明是一样的,却不能共用,会导致资源的浪费
(上面obj1.show==obj2.show-->false)
解决:用原型在所有创建的类上添加方法,使两个对象共用来自于原型上的方法
(这时有obj1.show==obj2.show-->true)
js面向对象最终的代码是:
function addPerson(name,qq){
//加new之后,系统自己会new一个对象出来,可不写:var this=new Object();
this.name=name;
this.myQQ=qq;
//加new之后,系统自己会返回一个对象出来,可不写:return this;
}
addPerson.prototype.show=function(){ //用原型在所用创建的类上添加方法
alert('我的姓名:'+this.name);
alert('我的QQ:'+this.myQQ);
}
var obj1=new addPerson('yufan','123456');
var obj2=new addPerson('red','456789');
obj1.show();
obj2.show();
alert(obj1.show==obj2.show); //true
总结面向对象创建的方法:
在构造函数上给对象添加属性,在原型上给对象添加方法
我们经常采用这种面向对象全新的写法:混合的构造函数/原型方式
8.js原型(prototype):类似CSS里面的class,用class时,可以一次给多个元素添加行外样式,
使用原型时,可以一次给多个实例化对象添加方法,使资源得到共用
var arr1=new Array(12,5,3);
var arr2=new Array(12,5,3,4);
arr1.sum=function(){ //arr1.sum方法相当于CSS里添加行间样式,一次只能给一个元素添加样式
var result=0;
for(var i=0;i<this.length;i++){
result+=this[i];
}
return result;
}
arr1.sum(); //正确
arr2.sum(); //会报错,因为没有为arr2添加sum方法
==>这时使用原型可以为多个对象添加方法,类似CSS里用class添加行外样式
var arr1=new Array(12,5,3);
var arr2=new Array(12,5,3,4);
Array.prototype.sum=function(){ //prototype原型在类上添加方法
var result=0;
for(var i=0;i<this.length;i++){
result+=this[i];
}
return result;
}
arr1.sum(); //正确
arr2.sum(); //正确
注**对象和类的区别
var arr=new Array(1,2,3);
--类:模子-->Array
--对象:成品(产品)-->arr
--prototype原型是往类里面加东西(Array.prototype.sum),而不是对象
js面向对象实例:
1.将一个面向过程的程序,改写成面向对象的形式
--原则:不能有函数套函数,但可以有全局变量
2.过程:将平时写的面向过程的js选项卡,改写成面向对象的js选项卡
--解决函数嵌套的问题(将嵌套的函数拿出来,放到外面,变成全局函数)
--解决局部变量的问题,当局部变量在多个函数中使用时,将局部变量变成全局变量(否则会报错)
--将window.onload(作用:初始化整个程序)变成 构造函数(作用:初始化整个对象)
--将全局变量变成 -->对象的属性
--将全局的函数变成 -->对象的方法
将面向过程的js选项卡,改写成面向对象的js选项卡
CSS代码: <style> .active{ background: red; } #div1 div{ 200px; height: 200px; background: #ccc; border:1px solid #000; display: none; margin-top: 20px; } </style> HTML代码: <div id="div1"> <input class="active" type="button" value="首页" /> <input type="button" value="新闻" /> <input type="button" value="咨询" /> <input type="button" value="教育" /> <div style="display: block;">1111</div> <div>2222</div> <div>3333</div> <div>4444</div> </div> JS代码: window.onload=function(){ var obj=new TabSwitch('div1'); }; function TabSwitch(id){ var _this=this; var oDiv=document.getElementById(id); this.aBtn=oDiv.getElementsByTagName('input'); this.aDiv=oDiv.getElementsByTagName('div'); for (var i = 0; i < this.aBtn.length; i++) { this.aBtn[i].index=i; this.aBtn[i].onclick=function(){ _this.btnClick(this); } } } TabSwitch.prototype.btnClick=function(oBtn){ for (var i = 0; i < this.aBtn.length; i++) { this.aBtn[i].className=''; this.aDiv[i].style.display='none'; } oBtn.className='active'; this.aDiv[oBtn.index].style.display='block'; }
3.改错:this,事件,闭包,传参
js面向对象高级:
1.json实现的面向对象:(又称单体)
var json={
name:'yufan',
qq:'123456',
showName:function(){
alert('我的名字叫:'+this.name);
},
showQQ:function(){
alert('我的QQ是:'+this.qq);
}
}
json.showName();
json.showQQ();
与OOP的方法相比json实现的创建对象优点是简单,但是该方法只适用创建单个对象,不适合多个对象
Json方式实现的对象的适用范围:
--整个程序里只有一个对象,写起来比较简单
2.命名空间:可以让很多相同名字的函数同时存在
--使用时,把方法包在一个json里面
var zns={};
zns.common={};
zns.ms={};
zns.color={};
zns.common.getUser=function(){
alert('a');
}
zns.ms.getUser=function(){
alert('b');
}
zns.color.getUser=function(){
alert('c');
}
zns.common.getUser();
zns.ms.getUser();
zns.color.getUser();
3.js中的引用问题:(函数不会出现js引用问题)
当把arr1给arr2时,计算机为了节约空间,会把arr1与arr2同时指向一个内存空间
而不是复制一份再赋给arr2,所以当改变arr2时,arr1也会发生改变,这个就叫js引用
var arr1=[1,2,3];
var arr2=arr1;
arr2.push(4);
alert(arr1); //1,2,3,4
alert(arr2); //1,2,3,4
==>解决js引用问题:
将arr2定义为一个空数组,这时arr1与arr2指向不同的内存空间
var arr1=[1,2,3];
var arr2=[];
for(var i=0;i<arr1.length;i++){
arr2.push(arr[i]);
}
arr2.push(4);
alert(arr1); //1,2,3
alert(arr2); //1,2,3,4
JS面向对象的继承:
1.通过call让B继承A的属性
2.通过B.prototype=A.prototype让B继承A的方法(会出现js引用问题)
解决A,B之间引用问题--通过for-in循环
for(var i in A.prototype){
B.prototype[i]=A.prototype[i];
}
3.继承详解:
function A(){
this.abc=12;
}
A.prototype.show=function(){
alert(this.abc);
}
//继承A
function B(){
//this-->new B
A.call(this); //本来给A添加属性,现在通过call改变A中的this,变成给B添加属性
}
B.prototype=A.prototype; //继承A的方法,但会出现js引用问题,让A和B同时指向一个内存空间
B.prototype.fn=function(){ //给子类B新添加属于自己独有的方法
alert('dec');
}
var objB=new B();
var objA=new A();
alert(objB.abc); //12
objB.show(); //12
objB.fn(); //dec
objA.fn(); //dec,这时子类B对象上的方法同样出现在A对象上面,而A对象不应该有,出现问题,是因为js引用的问题
//解决A,B之间引用问题-->通过for-in循环
JS继承最终代码:
function A(){
this.abc=12;
}
A.prototype.show=function(){
alert(this.abc);
}
//继承A
function B(){
//this-->new B
A.call(this); //本来给A添加属性,现在通过call改变A中的this,变成给B添加属性
}
//B.prototype=A.prototype; //会出现js引用问题,让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 A();
alert(objB.abc); //12
objB.show(); //12
objB.fn(); //abc
//objA.fn(); --这时再写这句话就会报错,所以应该去掉,因为A没有fn这个方法才是正确的
继承例子:
继承父类的拖拽,实现子类有限制范围的拖拽
<style media="screen">
#parentDiv{
350px;
height: 350px;
background: #ccc;
position: relative;
}
#div1{
150px;
height: 150px;
background: red;
position: absolute;
}
#div2{
100px;
height: 100px;
background: blue;
position: absolute;
}
</style>
<div id="parentDiv">
<div id="div1">父类拖拽</div>
<div id="div2">子类限制范围继承拖拽</div>
</div>
<script type="text/javascript">
window.onload=function(){
var dragDiv=new Drag('div1');
var limitDrag=new LimitDrag('div2');
}
//父类面向对象的拖拽
function Drag(id){
var _this=this;
this.disX=0;
this.disY=0;
this.oDiv=document.getElementById(id);
this.oDiv.onmousedown=function(ev){
_this.mouseDown(ev);
return false;
};
}
Drag.prototype.mouseDown=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.mouseMove(ev);
return false; //阻止拖动过程中选中文字的默认行为
};
document.onmouseup=function(){
_this.mouseUp();
};
}
Drag.prototype.mouseMove=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.mouseUp=function(){
document.onmousemove=null;
document.onmouseup=null;
}
//子类继承父类实现有限制范围的拖拽
//1.继承父类的属性
function LimitDrag(id){
Drag.call(this,id);
}
//2.继承父类的方法
for(var i in Drag.prototype){
LimitDrag.prototype[i]=Drag.prototype[i];
}
//3.重写,将子类与父类不同的地方进行重写
//(子类从父类那里已经继承一个mouseMove,这时重写将把原来的覆盖)
LimitDrag.prototype.mouseMove=function(ev){
var oEvent=ev||event;
var parentDiv=document.getElementById('parentDiv');
var l=oEvent.clientX-this.disX;
var t=oEvent.clientY-this.disY;
if (l<0) {
l=0;
}else if(l>parentDiv.offsetWidth-this.oDiv.offsetWidth){
l=parentDiv.offsetWidth-this.oDiv.offsetWidth;
}
if (t<0) {
t=0;
}else if(t>parentDiv.offsetHeight-this.oDiv.offsetHeight){
t=parentDiv.offsetHeight-this.oDiv.offsetHeight;
}
this.oDiv.style.left=l+'px';
this.oDiv.style.top=t+'px';
}
</script>
3.系统对象:(js里面的对象)
1)本地对象(非静态对象)
--需要经过实例化(new)的对象,才可以使用==>var arr=new Array(); arr.search();
--常用对象:Object,Function,Array,String,Boolean,Number,Date,RegExp,Error
2)内置对象(静态对象)
--不需要经过实例化(new)的对象,直接可以使用==>Math.ceil();
--常用:Global,Math
3)宿主对象(由浏览器提供的对象)
--对于JS的宿主,就是js的运行环境,一般指浏览器DOM,BOM
--宿主对象随着js运行环境的不同而不同(而1,2与js运行环境无关),
--如node中在后台编写代码,他就有新的js对象