面向对象与原型
工厂模式:
有个问题,识别问题,因为根本无法搞清楚他们到底是哪个对象的实例。box1和box2都是属于对象
function createObject(name,age){
var obj=new Object();
obj.name=name;
obj.age=age;
obj.run=function(){
return this.name+this.age+'运行中...';
};
return obj;
}
var box1=createObject('Lee',100);
var box2=createObject('Jack',200);
---------------------------------------------------------------------------------------------
构造函数模式
function Box(name,age){ //创建一个对象,所有构造函数的对象其实就是Object
this.name=name; //添加一个属性
this.age=age;
this.run=function(){ //添加一个方法
return this.name+this.age+'运行中...';
};
}
function Desk(name,age){ //创建一个对象,所有构造函数的对象其实就是Object
this.name=name; //添加一个属性
this.age=age;
this.run=function(){ //添加一个方法
return this.name+this.age+'运行中...';
};
}
//1.构造函数没有new Object,但它后台会自动var obj=new Object
//2.this就相当于obj
//3.构造函数不需要返回对象引用
创建的规范:
//1.构造函数也是函数,但函数名第一个字母大写
//2.必须new构造函数名(),new Box(),而这个Box第一个字母也是大写的
//3.必须使用new运算符
var box1=new Box('Lee',100);
var box2=new Box('Jack',100);
var box3=new Desk('kkk',100);
alert(box1.run());
alert(box2.run());
alert(box1 instanceof Box); //true
alert(box2 instanceof Box); //true
alert(box3 instanceof Box); //false 可以识别,因为box3是Desk对象的引用
-------------------------------------
function Box(name,age){
this.name=name;
this.age=age;
this.run=function(){
return this.name+this.age+'运行中...';
};
}
var box1=new Box('Lee',100); //实例化后地址为1
var box2=new Box('Lee',100); //实例化后地址为2
alert(box1.run==box2.run); //false 因为是引用类型
-------------------------------------
function Box(name,age){
this.name=name;
this.age=age;
this.run=run;
}
function run(){ //通过外面调用,保证引用地址一致
return this.name+this.age+'运行中...';
}
var box1=new Box('Lee',100);
var box2=new Box('Lee',100);
alert(box1.run==box2.run); //true
-------------------------------------------------------------------------------------------------
原型:
function Box(){} //构造函数函数体内什么都没有,这里如果有,叫做实例属性,实例方法
Box.prototype.name='Lee';
Box.prototype.age=100;
Box.prototype.run=function(){
return this.name+this.age+'运行中...';
}
var box1=new Box();
var box2=new Box();
alert(box1.run==box2.run); //true
alert(box1.__proto__); //[object Object] 这个属性是一个指针指向prototype原型对象
alert(box1.constructor); //构造属性,可以获取构造函数本身
//作用是被原型指针定位,然后得到的构造函数本身
//其实就是对象实例对应的原型对象的作用
isPrototypeOf
判断一个对象实例(对象引用)是不是指向了对象的原型对象
alert(Box.isPrototypeOf(box1));
function Box(){} //构造函数函数体内什么都没有,这里如果有,叫做实例属性,实例方法
Box.prototype.name='Lee';
Box.prototype.age=100;
Box.prototype.run=function(){
return this.name+this.age+'运行中...';
}
var box1=new Box();
//alert(Box.prototype.isPrototypeOf(box1)); //true
var obj=new Object();
alert(Object.prototype.isPrototypeOf(box1)); //true
delete box1.name; //删除实例中的属性
delete Box.prototype.name; //删除原型中的属性
Box.prototype.name='kkk'; //覆盖原型中的属性
---------------------------------------------------
hasOwnProperty
function Box(){} //构造函数函数体内什么都没有,这里如果有,叫做实例属性,实例方法
Box.prototype.name='Lee';
Box.prototype.age=100;
Box.prototype.run=function(){
return this.name+this.age+'运行中...';
}
var box1=new Box();
box1.name='Kac';
alert(box1.hasOwnProperty('name')); //true 判断实例中是否存在指定属性
--------------------------------------------------------
in
function Box(){} //构造函数函数体内什么都没有,这里如果有,叫做实例属性,实例方法
Box.prototype.name='Lee';
Box.prototype.age=100;
Box.prototype.run=function(){
return this.name+this.age+'运行中...';
}
var box1=new Box();
alert('name' in box1); //true 不管实例属性或原型属性是否存在,只要有就返回true,两边都没有,返回false
--------------------------------------------------------
判断只有原型中有属性:
function isProperty(object,property){ //object 是实例对象 property是属性
return !object.hasOwnProperty(property)&&(property in object)
}
--------------------------------------------------------
区别:
function Box(){}
Box.prototype.name='Lee';
Box.prototype.age=100;
Box.prototype.run=function(){
return this.name+this.age+'运行中...';
}
var box1=new Box();
alert(box1.constructor); //function Box(){}
function Box(){}
Box.prototype={
name:'Lee',
age:100,
run:function(){
return this.name+this.age+'运行中...';
}
};
var box=new Box();
alert(box.constructor); //function Object() { [native code] }
-------------------------------------
function Box(){}
Box.prototype={
constructor: Box, //强制指向Box
name:'Lee',
age:100,
run:function(){
return this.name+this.age+'运行中...';
}
};
var box=new Box();
alert(box.constructor); //function Box(){}
--------------------------------------------------------------------
function Box(){}
Box.prototype={
constructor: Box, //强制指向Box
name:'Lee',
age:100,
run:function(){
return this.name+this.age+'运行中...';
}
};
//重写了原型对象
Box.prototype={
age:20 //这里不会保留之前原型的任何信息了
};
var box=new Box();
alert(box.name); //undefined
--------------------------------------------------------------------
alert(Array.prototype.sort);
--------------------------------------------------------------------
//内置引用类型的功能扩展
String.prototype.addstring=function(){
return this+',被添加了!';
}
var box='Lee';
alert(box.addstring());
//ps:尽管给原生的内置引用类型添加方法使用起来特别方便,但我们不推荐使用这种方法。因为它可能会导致命名冲突,不利于代码维护。
--------------------------------------------------------------------
//原型的缺点
function Box(){}
Box.prototype={
constructor:Box,
name:'Lee',
age:100,
family:['哥哥','姐姐','妹妹'],
run:function(){
return this.name+this.age+'运行中...'
}
}
var box1=new Box();
alert(box1.family);
box1.family.push('弟弟');
alert(box1.family);
var box2=new Box();
alert(box2.family);
--------------------------------------------------------------------
//组合构造函数+原型模式
function Box(name,age){ //保持独立的用构造函数
this.name=name;
this.age=age;
this.family=['哥哥','姐姐','妹妹'];
}
Box.prototype={
constructor:Box,
run:function(){
return this.name+this.age+'运行中...'
}
}
var box1=new Box('Lee',100);
alert(box1.run());
var box2=new Box('Jack',200);
alert(box2.run());
--------------------------------------------------------------------
动态原型模式:
function Box(name,age){ //保持独立的用构造函数
this.name=name;
this.age=age;
this.family=['哥哥','姐姐','妹妹'];
Box.prototype.run=function(){
return this.name+this.age+'运行中...'
}
}
var box1=new Box('Lee',100);
var box2=new Box('Jack',200);
//原型的初始化,只要第一次初始化,就可以了,没必要每次构造函数实例化的时候都初始化
所以,看下面:
function Box(name,age){ //保持独立的用构造函数
this.name=name;
this.age=age;
this.family=['哥哥','姐姐','妹妹'];
if(typeof this.run!='function'){ //判断this.run是否存在
Box.prototype.run=function(){
return this.name+this.age+'运行中...'
}
}
}
var box1=new Box('Lee',100);
var box2=new Box('Jack',200);
--------------------------------------------------------------------
如果 动态原型模式不能满足,可以用寄生构造函数=工厂模式+构造函数,比较通用
function Box(name,age){
var obj=new Object();
obj.name=name;
obj.age=age;
obj.run=function(){
return this.name+this.age+'运行中...'
}
return obj;
}
var box1=new Box('Lee',100);
alert(box1.run());
var box2=new Box('Jack',200);
alert(box2.run());
--------------------------------------------------------------------
稳妥构造函数:构造函数中不使用this和实例化不使用new
function Box(){
var obj=new Object();
obj.name=name;
obj.age=age;
obj.run=function(){
return name+age+'运行中...'
}
return obj;
}
var box1=Box('Lee',100);
alert(box1.run());
var box2=Box('Jack',200);
alert(box2.run());
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
继承,通过原型链实现
function Box(){ //被继承的函数叫做超类型(父类,基类)
this.name='Lee';
}
function Desk(){ //继承的函数叫做子类型(子类,派生类)
this.age=100;
}
//通过原型链继承,超类型实例化后的对象实例,赋值给子类型的原型属性
//new Box()会将Box构造里的信息和原型里的信息都交给Desk
Desk.prototype=new Box();
var desk=new Desk();
alert(desk.name);
--------------------------------------------------------------
使用对象冒充继承
function Box(name,age){
this.name=name;
this.age=age;
//this.family=['哥哥','姐姐','妹妹']; //不会被共享
}
Box.prototype.family='家庭';
function Desk(name,age){
Box.call(this,name,age); //对象冒充
}
var desk=new Desk('Lee',100);
alert(desk.name);
alert(desk.family); //对象冒充,只能继承构造里的信息,原型里的继承不了
--------------------------------------------------------------
function Box(name,age){
this.name=name;
this.age=age;
this.family=['哥哥','姐姐','妹妹'];
}
Box.prototype.run=function(){
return this.name+this.age+'运行中...';
}
//构造函数里的方法,放在构造里,每次实例化,都会分配一个内存地址,浪费,所以最好放在原型里
function Desk(anme,age){
Box.call(this,name,age);
}
var desk=new Desk('Lee',100);
alert(desk.run()); //desk.run is not a function
--------------------------------------------------------------
组合继承: 对象冒充+原型链 重点,用的比较广泛
function Box(name,age){
this.name=name;
this.age=age;
this.family=['哥哥','姐姐','妹妹'];
}
Box.prototype.run=function(){
return this.name+this.age+'运行中...';
}
function Desk(anme,age){
Box.call(this,name,age); //对象冒充
}
Desk.prototype=new Box(); //原型链继承
var desk=new Desk('Lee',100);
alert(desk.run());
--------------------------------------------------------------------------------------------------------
之前讲的继承:1.原型链继承,2.借用构造函数继承(对象冒充继承) 3.组合继承(结合前两种)
4.原型式继承