一、面向对象编程的特点
1.抽象:
2.封装:
3.继承:
4.多态:
二、面向对象的组成
1.对象的属性:对象下面的变量。
2.对象的方法:对象下面的函数。
三、this指向
1.当用new去创建一个对象,构造函数中的this指向新创建出来的对象,而且函数的返回值默认是this(隐式返回)。
四、原型
作用:改写对象下面公用的方法和属性,让公用的方法或者属性在内存中存在一份(提高性能)。
五、包装对象
基本类型都有自己的包装对象:String Number Boolean
当基本类型的对象调用方法时,会先找到对应的包装对象类型,包装对象类型会把对象所有的属性和方法给基本类型,最后包装对象消失。
var str='hello';
str.charAt(0);//e,此处是调用了包装对象String下面的charAt()方法。
var str='hello';
str.number=10;//用包装对象创建对象添加属性
alert(str.number);//undefine,此时包装对象已经消失
六、原型链
1.定义:实例对象与原型之间的连接,叫做原型链。
2.proto(隐式连接)
3.Object对象类型是原型链的最外层
function Aaa(){
this.num=10;
}
Aaa.prototype.num=20;
Object.prototype.num=30;
var a1=new Aaa();
alert(a1.num);//10
function Aaa(){ }
Aaa.prototype.num=20;
Object.prototype.num=30;
var a1=new Aaa();
alert(a1.num);//20
function Aaa(){}
Object.prototype.num=30;
var a1=new Aaa();
alert(a1.num);//30
七、面向对象的一些属性和方法
1.hasOwnProperty():查看当前属性是不是对象自身下面的属性。
var arr=[];
arr.num=10;
Array.prototype.num2=20;
alert(arr.hasOwnProperty('num'));//true,arr所独有的属性
alert(arr.hasOwnProperty('num2'));//false,不是arr所独有的属性
2.constructor:查看对象的构造函数
例1:
function Aaa(){}
var a=new Aaa();
alert(a.constructor);//Aaa
例2:
var arr=[];
alert(arr.constructor);//Array
alert(arr.constructor==Array);//true
arr.constructor==Array可以用于数组类型的判断,但不是最好方法。
注意1:在写完一个函数后,系统会默认给该函数的原型添加一个constructor属性。
例如,创建如下函数:
function Aaa(){}
该函数的原型上默认自动生成一个constructor属性:
Aaa.prototype.constructor=Aaa;
所以有:
function Aaa(){}
var a=new Aaa();
alert(a.constructor);//Aaa
注意2: 系统自带属性for in不能获取到。
function Aaa(){}
Aaa.prototype.name='晓明';
Aaa.prototype.constructor=Aaa;
var a=new Aaa();
for(var attr in Aaa.prototype){
alert(attr);//可以获取到name,但是不能获取到系统自带的constructor
}
注意3:避免修改constructor属性。
function Aaa(){}
Aaa.prototype.name='晓明';
Aaa.prototype.age='24';
var a=new Aaa();
alert(a.constructor);//Aaa
如果把上面的属性改写成json的形式
function Aaa(){}
Aaa.prototype={
name:'晓明',
age:'24'
};
var a=new Aaa();
alert(a.constructor);//Object
Aaa.prototype.constructor被改写了!因为Aaa.prototype={};//Aaa.prototype=json,所以Aaa.prototype.constructor==Object。
正确的json写法中应重写constructor属性
function Aaa(){}
Aaa.prototype={
constructor:Aaa,//json中重写constructor属性
name:'晓明',
age:'24'
};
var a=new Aaa();
alert(a.constructor);//Aaa
八、instanceof:查看对象与构造函数是否在同一条原型链上。
例1:
function Aaa(){}
var a=new Aaa();
alert(a instanceof Aaa);//true,对象a和构造函数Aaa在同一条原型链上
alert(a instanceof Object);//true,对象a和构造函数Object在同一条原型链上
例2:
var arr=[];
alert(arr instanceof Array);//true
arr instanceof Array可用于数组类型的判断,但不是最好方法。
九、toString() :把对象转成字符串
1.系统对象自带toString,自定义的对象都是通过原型链找到Object.prototype的toString。
例1,对于自己写的对象
function Aaa(){}
var a=new Aaa();
alert(a.toString==Object.prototype.toString);//true
例2,对于系统对象
var arr=[];
alert(arr.toString==Object.prototype.toString);//false
alert(arr.toString==Array.prototype.toString);//true
2.toString()的用法
1)把对象转化成字符串。
var arr=[1,2,3];
alert(arr.toString());//'1,2,3'
2)进制转换
var num=255;
alert(num.toString(16));//'ff',将255转化为16进制
3)类型判断
例1,数组
var a=[];
alert(Object.prototype.toString.call(a));//[object Array]
例2,json
var a={};
alert(Object.prototype.toString.call(a));//[object Object]
例3,日期
var a=new Date();
alert(Object.prototype.toString.call(a));//[object Date]
例4,正则表达式
var a=new RegExp();
alert(Object.prototype.toString.call(a));//[object RegExp]
Object.prototype.toString.call(arr)=='[object Array]'可用于数组类型的判断,是最好方法。
拓展:哪种判断数组类型的方法最好呢?
toString方法最好,因为在iframe中创建数组,跨页面时,constructor方法和instanceof方法会失效。
window.onload=function(){
var oF=document.createElement('iframe');
document.body.appendChild(oF);
var ifArray=window.frames[0].Array;
var arr=new ifArray();//在iframe中创建数组,跨页面
alert(arr.constructor==Array);//false
alert(arr instanceof Array);//false
alert( Object.prototype.toString.call(arr)=='[object Array]');//true
};
十、对象的继承
1.什么是继承?
1)在原有对象的基础上,略作修改,得到一个新的对象。
2)不影响原有对象的功能
2.拷贝继承(通用型,有new或无new的时候都可以)
1)属性的继承:调用父类的构造函数call
2)方法的继承:for in 拷贝继承(jQuery中采用的也是拷贝继承)
function Father(name,age){
this.name=name;
this.age=age;
}
Father.prototype.showName=function(){
alert(this.name);
};
function Son(name,age,job){
Father.call(this,name,age);//属性继承,用call方法修改this指向
this.job=job;
}
extend(Son.prototype,Father.prototype);//方法继承,采用for in拷贝
//继承。虽然函数是对象,但是函数具有只能重新赋值(开辟新空间,变成新对
//象),不能被修改(在原来空间上修改旧对象)的特点,使它可以通过for in
//拷贝继承。
Son.prototype.showJob=function(){
alert(this.job);
};
function extend(objson,objfather){
for(var attr in objfather){
objson[attr]=objfather[attr];
}
}
var person=new Son('晓明','24','学生');
person.showName();//晓明
3.类式继承(适合new构造函数)
利用构造函数继承的方式。
JS中没有类的概念,把JS的构造函数看做类。
function Father(){
this.name='晓明';
}
Father.prototype.showName=function(){
alert(this.name);
};
function Son(){}
Son.prototype=new Father();//一句话实现继承,但存在很多问题
var s1=new Son();
s1.showName();//晓明
alert(s1.constructor);//Father
存在问题:
1.person.constructor指向Father而不是Son.
这是因为Son.prototype=new Father();这句话重写了Son.prototype,Son.prototype下原有的constructor等属性被覆盖。
解决:修正Son.prototype.constructor,Son.prototype.constructor=Son;
2.子类实例的属性均指向父类中的属性,会相互影响。
解决:属性和方法分别单独继承。
1)创建一个没有属性的空函数F,专门用来继承父类的方法。
2)属性采用call方法继承。
类式继承完整例子:
function Father(){
this.name=[1,2,3];
}
Father.prototype.showName=function(){
alert(this.name);
};
function Son(){
Father.call(this);//属性继承,用call方法修改this指向
}
//方法继承
var F=function(){};//创建一个没有属性的空函数F,专门用来继承父类的方法。
F.prototype=Father.prototype;
Son.prototype=new F();//一句话实现继承
Son.prototype.constructor=Son;
var s1=new Son();
s1.name.push(4);
s1.showName();//1,2,3,4
var s2=new Son();
alert(s2.name);//1,2,3。属性单独继承后,不同实例的属性相互独立,互不影响。
4.原型继承(适合无new的对象)
var father={
name:'晓明'
};
var son=extend(father);
son.name='小强';
alert(father.name);//晓明
alert(son.name);//小强
function extend(obj){
var F=function(){};
F.prototype=obj;
return new F();
}