一.什么是面向对象编程
1.用对象的思想去写代码,就是面向对象编程
我们以前常用的编程方式可以是比较过程式的写法,定义变量,然后给变量添加各种事件,如编写一个简单的选项卡,这样的写法有一个缺点,那就是复用性不高,假如页面上不止一个选项卡,那么同样的代码可能要出现很多次。
2.其实我们一直在使用对象
我们平时使用的Array,Date都是系统的内置对象
3.面向对象编程的特点,也可以说是优势:
1)抽象:抓住核心问题
2)封装:只能通过对象来访问方法
3)继承:从已有对象上继承出新的对象(代码复用)
4)多态:多对象的不同形态(同样是代码复用的方式,但是使用的比较少)
4.对象的组成
对象由属性和方法组成
对象下面的变量
我们称之为属性
,对象下面的函数
我们称之为方法
。
二、创建第一个面向对象程序
var obj = new Object(); //创建了一个空的对象
//给对象添加属性和方法
obj.name = '小明'; //属性
obj.showName = function(){ //方法
alert(this.name);
};
obj.showName();
其实这就是一个完整的面向对象程序了,看起来是不是很简单~
假设我们现在需要创建另外一个对象,那么我们只需要把代码再复制一遍,但是这样又有问题了,因为代码看起来不够优化,之前学习js的时候,学习到的思想就是如果有重复的代码,那么我们尽量把它封装成一个函数;在面向对象中,同样可以,只不过不叫封装函数了,我们称之为“工厂方式”。
function CreatePerson(name){
//1.原料
var obj = new Object();
//2.加工
obj.name = name;
obj.showName = function(){
alert( this.name );
};
//3.出厂
return obj;
}
var p1 = new CreatePerson('小明');
p1.showName();
var p2 = new CreatePerson('小强');
p2.showName();
这样看起来是不是简洁很多。
这里有两个新的概念,我们知道,其实我们在调用函数的时候,是可以直接调用的,像这样:
var p1 = CreatePerson('小明');
那么前面加上new,又有什么区别呢?
当new去调用一个函数 : 这个时候函数中的this就是创建出来的对象,而且函数的的返回值直接就是this(隐式返回)
另外new后面调用的函数 : 叫做构造函数
用来创建对象的函数,我们称之为构造函数。构造函数的特点:
1)首字母大写(参考系统对象写法)
2)New 关键字提取
3)This指向为新创建的对象
代码这样写同样还是存在问题,因为每创建一个对象,都要去创建一个方法,尽管这个方法做的是同一件事情,这样会造成内存浪费。
我们知道每一个对象都是有原型的,假设我们把方法加在原型上,那由原型构造的每一个对象就都拥有这个方法了。
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();
这样的话相同的方法在内存中就只存在一份了。
我们来总结一下面向对象的写法:
构造函数加属性,原型加方法
function 构造函数(){
this.属性
}
构造函数.原型.方法 = function(){};
var 对象1 = new 构造函数();
对象1.方法();
三、面向对象编程实践(1)-选项卡改写
1.原则:先写出普通的写法,然后改成面向对象写法
1)普通方法变型
尽量不要出现函数嵌套函数
可以有全局变量
把onload中不是赋值的语句放到单独函数中
2)改成面向对象
全局变量就是属性
函数就是方法
Onload中创建对象
改this指向问题(事件和定时器中this指向容易被修改)
普通写法:
html和css代码就不贴了
window.onload = function(){
var oWrap = document.getElementById('wrap');
var aBtn = document.getElementsByTagName('input');
var aDiv = oWrap.getElementsByTagName('div');
for (var i = 0; i < aBtn.length; i++) {
aBtn[i].index = i;
aBtn[i].onclick = function () {
for (var i = 0; i < aDiv.length; i++) {
aBtn[i].className = "";
aDiv[i].style.display = "none";
}
aDiv[this.index].style.display = "block";
aBtn[this.index].className = "active";
};
}
}
根据改写原则变形
var oWrap = null;
var aBtn = null;
var aDiv = null;
window.onload = function(){
oWrap = document.getElementById('wrap');
aBtn = oWrap.getElementsByTagName('input');
aDiv = oWrap.getElementsByTagName('div');
init();
};
//初始化函数
function init(){
for(var i=0;i<aBtn.length;i++){
aBtn[i].index = i;
aBtn[i].onclick = change;
}
}
function change(){
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';
}
呃。。改写之后好像更复杂了
继续改
function Tab(id) {
this.oWrap = document.getElementById(id);
this.aBtn = this.oWrap.getElementsByTagName('input');
this.aDiv = this.oWrap.getElementsByTagName('div');
this.iNow = 0;
}
Tab.prototype.init = function() {
var that = this;
for (var i = 0; i < that.aBtn.length; i++) {
that.aBtn[i].index = i;
that.aBtn[i].onclick = function () {
that.change(this);
};
}
};
Tab.prototype.change = function(obj) {
for (var i = 0; i < this.aDiv.length; i++) {
this.aBtn[i].className = "";
this.aDiv[i].style.display = "none";
}
this.aDiv[obj.index].style.display = "block";
obj.className = "active";
};
var t1 = new Tab("wrap"); //传参是为了方便复用
t1.init();//没用window.onload,那就写在后面,否则无法调用
这里this、that傻傻分不清的,请看这里:函数进阶
这样看起来虽然还是没有普通写法简单,但是如果要复用的话就方便多了,另外面向对象编程比较适用于复杂的项目。
假如页面上还有另外一个选项卡,而且这个选项卡要求是自动播放的,那么我们只需要在原来的基础上加上:
Tab.prototype.autoPaly = function () {
var that = this;
setInterval(function() {
if(that.iNow == that.aBtn.length-1){
that.iNow = 0;
}
else{
that.iNow++;
}
for (var i = 0; i < that.aDiv.length; i++) {
that.aBtn[i].className = "";
that.aDiv[i].style.display = "none";
}
that.aDiv[that.iNow].style.display = "block";
that.aBtn[that.iNow].className = "active";
}, 2000);
};
var t2 = new Tab("wrap2");
t2.init();
t2.autoPaly();
四、面向对象编程实践(2)-拖拽改写
这里要特别注意一下event对象的位置。
window.onload = function () {
var d1 = new Drag('div1');
d1.init();
};
//构造函数Drag
function Drag(id) {
this.oDiv = document.getElementById(id);
this.disX = 0;
this.disY = 0;
}
//初始化方法
Drag.prototype.init = function () {
var that = this;
this.oDiv.onmousedown = function (e) {
e = e||window.event; //event只能出现在事件函数当中,所以不能写在fnDown方法里面
that.fnDown(e);
return false;
};
};
Drag.prototype.fnDown = function(e) {
var that = this;
this.disX = e.clientX - this.oDiv.offsetLeft;
this.disY = e.clientY - this.oDiv.offsetTop;
document.onmousemove = function(e){
e = e||window.event;
that.fnMove(e);
};
document.onmouseup = this.fnUp;//注意这里别加括号。。踩过的坑
};
Drag.prototype.fnMove = function(e) {
this.oDiv.style.left = e.clientX - this.disX +'px';
this.oDiv.style.top = e.clientY - this.disY + 'px';
};
Drag.prototype.fnUp = function() {
document.onmousemove = null;
document.onmouseup = null;
};