JS 面向对象及组件开发
 
JS的面向对象:
 
1、什么是面向对象编程
 
用对象的思想去写代码,就是面向对象编程
过程式写法
面向对象写法
我们一直都在使用对象
数组 Array 时间 Date
var date = new Date();
var arr = new Array(); //[] //我们把系统自带的对象,叫做系统对象
面向对象编程(OOP)的特点
抽象:抓住核心问题
封装:只能通过对象来访问方法
继承:从已有对象上继承出新的对象
多态:多对象的不同形态
 
2、对象的组成
 
方法(行为、操作)——函数:过程、动态的
属性——变量:状态、静态的
 
var arr = [];
arr.number = 10; //对象下面的变量:叫做对象的属性
arr.test = function(){ //对象下面的函数 : 叫做对象的方法
alert(123);
};
 
arr.test(); //123
 
3、创建第一个面向对象程序
 
为对象添加属性和方法
Object对象
this指向
创建两个对象 : 重复代码过多
 
//var obj = {};
var obj = new Object(); //创建了一个空的对象
obj.name = '小明'; //属性
obj.showName = function(){ //方法
 
//alert(obj.name);
alert(this.name); // this指向的就是obj
 
};
 
obj.showName(); //小明
 
4、工厂方式
 
//工厂方式 : 面向对象中的封装函数
 
function createPerson(name){
 
 
}
 
var p1 = createPerson('小明');
p1.showName();
var p2 = createPerson('小强');
p2.showName();
 
5、对象的引用
 
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]; // b又重新占了一个内存地址,和原来的无关
alert(b); //[1,2,3,4]
alert(a); //[1,2,3]
 
var a = 5;
var b = 5;
alert(a == b); //基本类型 : 值相同就可以
 
var a = [1,2,3];
var b = [1,2,3];
alert( a == b ); //false //对象类型 : 值和引用都相同才行
 
var a = [1,2,3];
var b = a;
alert( a==b ); //true
 
6、工厂方式,构造函数的写法:
 
首字母大写、New 关键字提取、This指向为新创建的对象
 
当new去调用一个函数 : 这个时候函数中的this就是创建出来的对象,而且函数的的返回值直接就是this(隐式返回)
 
构造函数:new后面调用的函数,即用来创建对象的函数,叫做构造函数
 
// CreatePerson()构造函数:
function CreatePerson(name){
 
//省略new Object和最后的return obj
 
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 ,值虽然相同,但是引用的 内存地址不同
 
存在的问题:对象的引用、浪费内存
 
7、原型-prototype
 
原型 : 重写对象方法,让相同方法在内存中存在一份。就是去改写对象下面公用的方法或者属性 , 让公用的方法或者属性在内存中存在一份 ( 提高性能 )
 
原型 : CSS中的class,可以重用,但优先级没style高
普通方法 : CSS中的style,不可以重用,优先级高
 
即原型可以重用,但优先级没有普通方法高。
 
var arr = [];
arr.number = 10;
Array.prototype.number = 20;
 
alert(arr.number); //10
 
 
普通方法:
 
var arr = [1,2,3,4,5];
var arr2 = [2,2,2,2,2];
 
arr.sum = function(){
 
var result = 0;
for(var i=0;i<this.length;i++){
result += this[i];
}
return result;
 
};
arr2.sum = function(){
 
var result = 0;
for(var i=0;i<this.length;i++){
result += this[i];
}
return result;
 
};
 
alert( arr.sum() ); //15
alert( arr2.sum() ); //10
 
原型方法 :
 
var arr = [1,2,3,4,5];
var arr2 = [2,2,2,2,2];
 
Array.prototype.sum = function(){
var result = 0;
for(var i=0;i<this.length;i++){
result += this[i];
}
return result;
};
 
alert( arr.sum() ); //15
alert( arr2.sum() ); //10
 
8、工厂方式之原型:面向对象的写法:
 
原型prototype : 要写在构造函数的下面
 
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
 
总结面向对象写法:构造函数加属性,原型加方法
 
function 构造函数(参数){
this.属性 = 参数;
}
构造函数.prototype.方法 = function(){ ... };
 
 
 
调用写法:
 
var 对象1 = new 构造函数();
对象1.方法();
 
 
9、面向对象的例子:
 
原则:
1)先写出普通的写法,然后改成面向对象写法
2)普通方法变型
3)尽量不要出现函数嵌套函数
4)可以有全局变量
5)把onload中不是赋值的语句放到单独函数中
 
改成面向对象:
1)全局变量就是属性
2)函数就是方法
3)Onload中创建对象
4)改this指向问题
5)事件ev要放到事件函数中:
var ev = ev || window.event;
return false;
 
 
 
 
例子:面向对象的选项卡:
 
第一步:普通方法:
 
<script>
 
window.onload = function(){
 
}
 
};
 
</script>
 
第二步:
先变型:
尽量不要出现函数嵌套函数
可以有全局变量
把onload中不是赋值的语句放到单独函数中
 
 
 
<script>
 
var oParent = null;
var aInput = null;
var aDiv = null;
 
window.onload = function(){
 
oParent = document.getElementById('div1');
aInput = oParent.getElementsByTagName('input');
aDiv = oParent.getElementsByTagName('div');
 
init();
 
};
 
function init(){
for(var i=0;i<aInput.length;i++){
aInput[i].index = i;
aInput[i].onclick = change;
}
}
 
function change(){
for(var i=0;i<aInput.length;i++){
aInput[i].className = '';
aDiv[i].style.display = 'none';
}
this.className = 'active';
aDiv[this.index].style.display = 'block';
}
 
</script>
 
 
第三步:
 
全局变量就是属性
函数就是方法
Onload中创建对象
改this指向问题
 
 
 
<script>
 
window.onload = function(){
 
var t1 = new Tab('div1');
t1.init();
t1.autoPlay();
 
var t2 = new Tab('div2');
t2.init();
t2.autoPlay();
 
};
 
function Tab(id){
this.oParent = document.getElementById(id);
this.aInput = this.oParent.getElementsByTagName('input');
this.aDiv = this.oParent.getElementsByTagName('div');
this.iNow = 0;
}
 
Tab.prototype.init = function(){
var This = this;
for(var i=0;i<this.aInput.length;i++){
this.aInput[i].index = i;
this.aInput[i].onclick = function(){
This.change(this);
};
}
};
 
Tab.prototype.change = function(obj){
for(var i=0;i<this.aInput.length;i++){
this.aInput[i].className = '';
this.aDiv[i].style.display = 'none';
}
obj.className = 'active';
this.aDiv[obj.index].style.display = 'block';
};
 
Tab.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';
 
},2000);
 
};
 
</script>
 
 
10、包装对象 : JS基于原型的程序、系统对象也是基于原型的程序
 
尽量不要去修改或者添加系统对象下面的方法和属性
 
基本类型都有自己对应的包装对象 : String Number Boolean
 
基本类型会找到对应的包装对象类型,然后包装对象把所有的属性和方法给了基本类型,然后包装对象消失
 
 
var str = 'hello';
 
String.prototype.lastValue = function(){
return this.charAt(this.length-1);
};
 
alert( str.lastValue() ); // o
 
 
 
var str = 'hello';
 
str.number = 10; //创建对象后,包装对象立即消失
 
alert( str.number ); //undefined 创建的新对象
 
 
11、原型链
 
原型链 : 实例对象与原型之间的连接,叫做原型链
 
原型链的最外层 : Object.prototype
 
对象调用的属性在构造函数中没有的话,会沿着原型链到该对象的prototype原型中查找,若还是没有,则沿着最外层原型链到Object.prototype中查找
 
 
function Aaa(){
this.num = 10; // 优先级最高
}
Aaa.prototype.num = 20; // 优先级第二
Object.prototype.num = 30; //优先级最后
 
var a1 = new Aaa();
alert(a1.num);
 
 
12、hasOwnProperty : 看是不是对象自身下面的属性
 
var arr = [];
arr.num = 10;
Array.prototype.num2 = 20;
 
alert( arr.hasOwnProperty('num') ); //true //只是arr中的属性,其余的数组对象没有
 
alert( arr.hasOwnProperty('num2') ); //false //数组对象原型中的属性,所有数组都有这个属性
 
alert( arr.hasOwnProperty == Object.prototype.hasOwnProperty ); //true // 这个属性是在最外层的Object原型上
 
 
 
13、constructor : 查看对象的构造函数
 
function Aaa(){
}
 
var a1 = new Aaa();
 
alert( a1.constructor ); //Aaa
 
var arr = [];
alert( arr.constructor == Array ); //true
 
 
function Aaa(){
}
Aaa.prototype.constructor = Aaa; //每一个函数都会有的,都是自动生成的
 
Aaa.prototype.constructor = Array; // 修改了对象的构造函数,避免这样做
 
 
function Aaa(){
}
 
Aaa.prototype.name = '小明';
Aaa.prototype.age = 20;
 
var a1 = new Aaa();
alert( a1.constructor );
 
//若用JSON形式写Aaa的属性,那么a1的constructor不是Aaa了,而是JSON对象,即Object
Aaa.prototype = {
constructor : Aaa,
name : '小明',
age : 20
};
 
 
 
function Aaa(){
}
 
Aaa.prototype.name = 10;
Aaa.prototype.constructor = Aaa;
 
for( var attr in Aaa.prototype ){ //遍历不到JS内置属性,只能遍历到name
alert(attr);
}
 
 
 
14、instanceof : 对象与构造函数在原型链上是否有关系
 
//自定义对象
function Aaa(){
}
 
var a1 = new Aaa();
 
alert( a1 instanceof Object ); //true
 
//系统内置对象
var arr = [];
 
alert( arr instanceof Array ); //true
 
 
15、toString() :
 
toString() : 系统对象下面都是自带的,不需要经过原型链寻。自己写的对象都是通过原型链找Object下面的。
 
var arr = [];
alert( arr.toString == Object.prototype.toString ); //false
 
/function Aaa(){
}
var a1 = new Aaa();
alert( a1.toString == Object.prototype.toString ); //true
 
 
toString() : 把对象转成字符串
 
var arr = [1,2,3];
 
Array.prototype.toString = function(){
return this.join('+');
};
 
alert( arr.toString() ); //'1+2+3'
 
 
toString() : 进制转换
var num = 255;
alert( num.toString(16) ); //'ff' //255转成16进制
 
 
利用toString做类型的判断 : (推荐)
 
var arr = [];
 
alert( Object.prototype.toString.call(arr) == '[object Array]' ); //'[object Array]'
 
用constructor和instanceof判断类型在iframe中判断不出
 
alert( arr.constructor == Array ); //false
alert( arr instanceof Array ); //false
 
 
 
16、继承
 
继承 :在原有对象的基础上,略作修改,得到一个新的对象。不影响原有对象的功能。
 
子类不影响父类,子类可以继承父类的一些功能 ( 代码复用 )
 
1)拷贝继承:
 
属性的继承 : 调用父类的构造函数 call
 
方法的继承 : for in : 拷贝继承 (jquery也是采用拷贝继承extend)
 
function CreatePerson(name,sex){ //父类
this.name = name;
this.sex = sex;
}
CreatePerson.prototype.showName = function(){
alert( this.name );
};
 
var p1 = new CreatePerson('小明','男');
//p1.showName();
 
 
function CreateStar(name,sex,job){ //子类
 
CreatePerson.call(this,name,sex); //继承 call改变this指向为对象
 
this.job = job;
 
}
 
//不能用对象的赋值,CreateStar.prototype = CreatePerson.prototype; 都指向同一内存地址,改变其中一个,另一个也会改变
 
extend( CreateStar.prototype , CreatePerson.prototype );
 
CreateStar.prototype.showJob = function(){
};
 
var p2 = new CreateStar('黄晓明','男','演员');
 
p2.showName();
 
 
function extend(obj1,obj2){ //把父类所有的非对象属性给子类
for(var attr in obj2){
obj1[attr] = obj2[attr];
}
}
 
 
 
 
2)类式继承:
 
类 : JS是没有类的概念的 , 把JS中的构造函数看做的类
 
要做属性和方法继承的时候,要分开继承,避免子类对象之间的修改相互影响属性
 
属性的继承 : 调用父类的构造函数 call
 
方法的继承 : 利用构造函数(类)继承的方式
 
 
function Aaa(){ //父类
this.name = [1,2,3];
}
Aaa.prototype.showName = function(){
alert( this.name );
};
 
 
function Bbb(){ //子类 ,属性的继承
 
Aaa.call(this);
 
}
 
//方法的继承
var F = function(){};
F.prototype = Aaa.prototype; //只能继承方法
Bbb.prototype = new F();
Bbb.prototype.constructor = Bbb; //修正指向问题
 
var b1 = new Bbb();
b1.name.push(4);
alert( b1.name ); //[1,2,3,4]
 
var b2 = new Bbb();
alert( b2.name );//[1,2,3]
 
 
 
3)原型继承:
 
借助原型来实现对象继承对象
 
var a = {
name : '小明'
};
 
var b = cloneObj(a);
 
b.name = '小强';
 
alert( b.name );//小强
alert( a.name );//小明
 
function cloneObj(obj){
 
var F = function(){};
 
F.prototype = obj;
 
return new F();
 
}
 
 
拷贝继承: 通用型的 有new或无new的时候都可以
 
类式继承: new构造函数
 
原型继承: 无new的对象
 
17、组件开发 : 多组对象,像兄弟之间的关系( 代码复用的一种形式 )
 
对面向对象的深入应用(UI组件,功能组件)
将 配置参数、方法、事件,三者进行分离
 
 
18、自定义事件 : 主要是跟函数有关系,就是让函数能够具备事件的某些特性
 
window.addEventListener('show',function(){
alert(1);
},false);
window.addEventListener('show',function(){
alert(2);
},false);
window.addEventListener('show',function(){
alert(3);
},false);
 
show(); //主动触发自定义事件
05-11 21:54