JS面向对象编程
面向对象编程的特点:
封装 :将数据和对数据的操作集成在一起
继承 :一个类型的对象可以访问另外一个类型的属性和方法
多态 :同一个方法作用于不同的对象会有不同的结构
对象的组成:
- 属性:对象下面的变量叫做对象的属性
- 方法:对象下面的函数叫做对象的方法
var arr = [];
arr.number = 10; //对象下面的变量:叫做对象的属性
//alert( arr.number );
//alert( arr.length );
arr.test = function(){ //对象下面的函数 : 叫做对象的方法
alert(123);
};
arr.test();//方法
arr.push();//方法
arr.sort();
创建一个对象
var obj=new Object();//创建一个空的对象
obj.name='小明'; //属性
obj.showName=function(){ //方法
alert(this.name);//this指向obj
}
obj.showName();//小明
如果需要创建两个或多个对象
var obj1=new Object();//创建一个空的对象
obj1.name='小明'; //属性
obj1.showName=function(){ //方法
alert(this.name);//this指向obj
}
obj1.showName();//小明
var obj2=new Object();//创建一个空的对象
obj2.name='小灰'; //属性
obj2.showName=function(){ //方法
alert(this.name);//this指向obj
}
obj2.showName();//小灰
使用Object函数或对象字面量都可以创建面向对象,但需要创建多个对象时,会产生大量的重复代码,可通过工厂方式来解决这个问题
工厂方式 -------------------- 面向对象中的封装函数
//工厂方式 : 封装函数
function createPerson(name){
var obj = new Object();
obj.name = name;
obj.showName = function(){
alert( this.name );
};
return obj;
}
var p1 = createPerson('小明');
p1.showName();
var p2 = createPerson('小强');
p2.showName();
使用自定义的构造函数,定义对象类型的属性和方法,与工厂方式的区别:
- 没有显式的创建对象
- 直接将属性和方法赋给this对象
- 没有return语句
上面例子中:CreatePerson构造函数生成的两个对象p1与p2都是CreatePerson的实例
虽然构造函数解决了上面工厂方式的问题,但是它一样存在缺点,就是在创建对象时,每个对象都有一套自己的方法,
每定义一个函数都实例化了一个对象
例如:
function CreatePerson(name){
this.name = name;
this.showName = function(){
alert( this.name );
};
}
var p1 = new CreatePerson('小明');
//p1.showName();
var p2 = new CreatePerson('小强');
//p2.showName();
alert( p1.showName == p2.showName ); //false 它们的值相同,地址不同
测试例子中的p1.showName与p2.showName是否会相等,弹出的结果是false,说明p1和p2实例都包含一个不同的showName实例
再来举几个例子:
var a = [1,2,3];
var b = [1,2,3];
alert( a == b ); //false 值相同,地址不同
var a = 5;
var b = a;
b += 3
alert(b); //8
alert(a); //5 基本类型 : 赋值的时候只是值的复制
var a = [1,2,3];
var b = a;
b.push(4);
alert(b); //[1,2,3,4]
alert(a); //[1,2,3,4] 对象类型 : 赋值不仅是值的复制,而且也是引用的传递
var a = [1,2,3];
var b = a;
b = [1,2,3,4];
alert(b); //[1,2,3,4]
alert(a); //[1,2,3]
对比上面的几个例子,不难看出基本类型和对象类型的区别了,对象类型的赋值不仅是值的复制,也是引用的传递;提到了对象的引用应该很清楚上述p1.showName==p2.showName为何会返回结果是false
构造函数
构造函数:一个普通函数,当和new一起使用时,称之为构造函数
加new 构造函数的执行过程
1.开辟空间存储对象
2.把this设置为当前的对象
3.设置属性和方法的值
4.把this对象返回
function Person(name,age){ //Person类
this.name = name;
this.age = age;
this.sayHello = function(){
console.log(this.name);
}
}
function Animal(name,age){//Animal 类
this.name = name;
this.age = age;
this.sayHello = function(){
console.log(this.name);
}
}
var person1 = new Person("john1",21);
var person2 = new Person("john2",22);
console.log(person1.sayHello == person2.sayHello);//false
//每创建一个实例都会新创建一个代码相同的方法,消耗内存
console.log(person1.name);//join1
person1.sayHello();//join1
var animal1 = new Animal("miao",2);
console.log(person1 instanceof Person,animal1 instanceof Person);//true false
console.log(person1 instanceof Object,animal1 instanceof Object);//true true
原型模式(prototype) -------------------- 给一类对象添加方法
每个函数都有的属性 每一个构造函数都有一个原型对象prototype
每一个原型对象都有一个指向构造函数的指针 console.dir(Person)
原型对象的实例和方法都能被实例访问
原型(prototype):重写对象下面公用的属性或方法,让公用的属性或方法在内存中只存在一份(提高性能),也就是说所有在原型对象中创建的属性或方法都直接被所有对象实例共享。
- 原型:类比css中的class
- 普通方法:类比css中的style
var arr = [1,2,3,4,5];
var arr2 = [2,2,2,2,2];
Array.prototype.sum = function(){//原型prototype : 要写在构造函数的下面
var result = 0;
for(var i=0;i<this.length;i++){
result += this[i];
}
return result;
};
alert( arr.sum() ); //15
alert( arr2.sum() ); //10
原型优先级:如果在实例中添加了一个属性,而该属性与实例原型中的一个属性同名,该属性将会屏蔽原型中的那个属性
例子1:
var arr = [];
arr.number = 10;
Array.prototype.number = 20;
alert(arr.number);//10
例子2:
Array.prototype.a=12;//原型属性
var arr=[1,2,3];
alert(arr.a);//12
arr.a=5;//实例属性
alert(arr.a);//5
function Person(){
}
//console.dir(Person);
Person.prototype.name = "john";
Person.prototype.age = "20";
Person.prototype.sayHello = function(){
console.log(this.name);
}
var person1 = new Person();
var person2 = new Person();
console.log(person1.sayHello == person2.sayHello);
console.log(person1.name,person2.name);
//具体参数无法传递
所有的name age一样
工厂方式之原型
function CreatePerson(name){//普通方法
this.name=name;
}
CreatePerson.prototype.showName=function(){//原型
alert(this.name);
}
var p1=new CreatePerson('小明');
p1.showName();
var p2=new CreatePerson('小强');
p2.showName();
alert( p1.showName== p2.showName);//true
由上述例子中:p1.showName== p2.showName弹出的结果是true,可见原型解决了构造函数中“每定义一个函数都实例化了一个对象”的问题
原型的运用
选项卡实例:
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title>选项卡</title>
<style>
#div1 div{
width:400px;
height:300px;
border:1px solid #ccc;
overflow: hidden;
display: none;
margin: 15px 0;
}
#div1 input{
color: #fff;
width:100px;
height:40px;
background: darkseagreen;
border:none;
font-size: 14px;
letter-spacing: 5px;
}
#div1 p{
font-size: 20px;
line-height: 24px;
text-align: center;
color:darkgreen;
}
#div1 .title{
padding: 0;
font-weight: bold;
}
#div1 .active{
background:sandybrown;
color:#fff;
}
</style>
<script>
window.onload=function(){
var oDiv=document.getElementById('div1');
var aInput=oDiv.getElementsByTagName('input');
var aDiv=oDiv.getElementsByTagName('div');
var i=0;
for(i=0;i<aInput.length;i++){
aInput[i].index=i;
aInput[i].onmousemove=function(){
for(var i=0;i<aInput.length;i++){
aInput[i].className='';
aDiv[i].style.display='none';
}
aInput[this.index].className='active';
aDiv[this.index].style.display='block';
}
}
}
</script>
</head>
<body>
<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;">
<p class="title">落 花</p>
<p class="author">李商隐</p>
<p>高阁客竟去,小园花乱飞。</p>
<p>参差连曲陌,迢递送斜晖。</p>
<p>肠断未忍扫,眼穿仍欲归。</p>
<p>芳心向春尽,所得是沾衣。</p>
</div>
<div>
<p class="title">蜀 相</p>
<p class="author">杜甫</p>
<p>丞相祠堂何处寻,锦官城外柏森森。</p>
<p>映阶碧草自春色,隔叶黄鹂空好音。</p>
<p>三顾频烦天下计,两朝开济老臣心。</p>
<p>出师未捷身先死,长使英雄泪满襟。</p>
</div>
<div>
<p class="title">八阵图</p>
<p class="author">杜甫</p>
<p>功盖三分国,名成八阵图。</p>
<p>江流石不转,遗恨失吞吴。</p>
</div>
<div>
<p class="title">泊秦淮</p>
<p class="author">杜牧</p>
<p>烟笼寒水月笼沙,夜泊秦淮近酒家。</p>
<p>商女不知亡国恨,隔江犹唱后庭花。</p>
</div>
</div>
</body>
</html>
效果(鼠标经过按钮时选项卡切换):
面向对象选项卡:
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title>选项卡</title>
<style>
#div1 div,#div2 div{
width:400px;
height:300px;
border:1px solid #ccc;
overflow: hidden;
display: none;
margin: 15px 0;
}
#div1 input,#div2 input{
color: #fff;
width:100px;
height:40px;
background: darkseagreen;
border:none;
font-size: 14px;
letter-spacing: 5px;
}
#div1 p,#div2 p{
font-size: 20px;
line-height: 24px;
text-align: center;
color:darkgreen;
}
#div1 .title,#div2 .title{
padding: 0;
font-weight: bold;
}
#div1 .active,#div2 .active{
background:sandybrown;
color:#fff;
}
</style>
<script>
window.onload=function(){
var t1=new TabSwitch('div1');
t1.switch();
var t2=new TabSwitch('div2');//面向对象的复用性
t2.switch();
t2.autoPlay();
/*alert(t2.switch==t1.switch);//ture*/
}
function TabSwitch(id){
this.oDiv=document.getElementById(id);
this.aInput=this.oDiv.getElementsByTagName('input');
this.aDiv=this.oDiv.getElementsByTagName('div');
this.iNow=0;//自定义属性
}
TabSwitch.prototype.switch=function(){//原型
for(var i=0;i<this.aInput.length;i++){
var This=this;//将指向面向对象的this保存下来
this.aInput[i].index=i;
this.aInput[i].onmousemove=function(){
This.tab(this);//This指向面向对象 this指向this.aInput[i]
}
}
}
TabSwitch.prototype.tab=function(obj){//原型
for(var i=0;i<this.aInput.length;i++){
this.aInput[i].className='';
this.aDiv[i].style.display='none';
}
this.aInput[obj.index].className='active';
this.aDiv[obj.index].style.display='block';
}
//自动播放
TabSwitch.prototype.autoPlay=function(){
var This=this;
setInterval(function(){
if(This.iNow==This.aInput.length-1){
This.iNow=0;
}
else{
This.iNow++;
}
for(var i=0;i<This.aInput.length;i++){
This.aInput[i].className='';
This.aDiv[i].style.display='none';
}
This.aInput[This.iNow].className='active';
This.aDiv[This.iNow].style.display='block';
},1000);
}
</script>
</head>
<body>
<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;">
<p class="title">落 花</p>
<p class="author">李商隐</p>
<p>高阁客竟去,小园花乱飞。</p>
<p>参差连曲陌,迢递送斜晖。</p>
<p>肠断未忍扫,眼穿仍欲归。</p>
<p>芳心向春尽,所得是沾衣。</p>
</div>
<div>
<p class="title">蜀 相</p>
<p class="author">杜甫</p>
<p>丞相祠堂何处寻,锦官城外柏森森。</p>
<p>映阶碧草自春色,隔叶黄鹂空好音。</p>
<p>三顾频烦天下计,两朝开济老臣心。</p>
<p>出师未捷身先死,长使英雄泪满襟。</p>
</div>
<div>
<p class="title">八阵图</p>
<p class="author">杜甫</p>
<p>功盖三分国,名成八阵图。</p>
<p>江流石不转,遗恨失吞吴。</p>
</div>
<div>
<p class="title">泊秦淮</p>
<p class="author">杜牧</p>
<p>烟笼寒水月笼沙,夜泊秦淮近酒家。</p>
<p>商女不知亡国恨,隔江犹唱后庭花。</p>
</div>
</div>
<div id="div2">
<input class="active" type="button" value="五言律诗">
<input type="button" value="七言律诗">
<input type="button" value="五言绝句">
<input type="button" value="七言绝句">
<div style="display: block;">
<p class="title">落 花</p>
<p class="author">李商隐</p>
<p>高阁客竟去,小园花乱飞。</p>
<p>参差连曲陌,迢递送斜晖。</p>
<p>肠断未忍扫,眼穿仍欲归。</p>
<p>芳心向春尽,所得是沾衣。</p>
</div>
<div>
<p class="title">蜀 相</p>
<p class="author">杜甫</p>
<p>丞相祠堂何处寻,锦官城外柏森森。</p>
<p>映阶碧草自春色,隔叶黄鹂空好音。</p>
<p>三顾频烦天下计,两朝开济老臣心。</p>
<p>出师未捷身先死,长使英雄泪满襟。</p>
</div>
<div>
<p class="title">八阵图</p>
<p class="author">杜甫</p>
<p>功盖三分国,名成八阵图。</p>
<p>江流石不转,遗恨失吞吴。</p>
</div>
<div>
<p class="title">泊秦淮</p>
<p class="author">杜牧</p>
<p>烟笼寒水月笼沙,夜泊秦淮近酒家。</p>
<p>商女不知亡国恨,隔江犹唱后庭花。</p>
</div>
</div>
</body>
</html>
组合创建
属性放到构造函数里 方法放到原型对象上
function Person(name,age){
var count = 10;//私有属性
this.name = name;//实例属性
this.age = age;
this.init = function(){//实例方法
console.log(count);
}
}
Person.prototype.sayHello = function(){ //原型方法
console.log(this.name);
console.log(count);
}
var person1 = new Person("john1",21);
var person2 = new Person("john2",22);
console.log(person1.sayHello == person2.sayHello);
console.log(person1.name,person2.name);
person1.sayHello();
好了 ok了 面向对象就是这样....