javascript 高级面向对象

来源:互联网 发布:scratch软件 编辑:程序博客网 时间:2024/05/16 09:20

 通过 new Object 得到

varperson = newObject();
person.age =18;
person.name ="小石头
";
person.say =
function() {
//
必须加this,指向person对象所定义的属性
alert("我的名字是:"+this.name+",我今年"+this.age+"岁了");
}
person.say();

但是因为没有类的约束,所以这两种情况都无法实现对象的重复使用,所以如果定义很多的对象的话就要一个一个的去写,这样太过于麻烦,在实际的操作过程中也存在一定的问题,这个时候就可以使用工厂的模式去创建很多的对象。例如:

function Person(name,age){
var p=new Object();
p.name=name;
p.age=age;
p.say=function(){
alert("名字"+this.name+",年龄"+this.age);
}
return p;
}
var p1=Person("小石头",22);
p1.say();
var p2=Person("鸡棚",33);
p2.say();

虽然json 的方式也可以定义对象,但是它和new Object 一样存在了不能对象重用的缺陷所以大家研究出了一种工厂方式来定义一个对象, 下面我们来使用工厂方式来实现一个对象的定义。
因为上面两种方式定义对象无法让对象重复使用,所以在使用的过程中大家摸索出来一种基于工厂模式的

定义方式。例如:

function Person(name,age){
this.name = name;
this.age = age;
this.say =function(){
alert("我的名字叫:"+this.name+"我的年龄:"+this.age);
}
}

var p1 = new Person("小石头",38);
var p2 = new Person("鸡棚",28);
p1.say();
p2.say();

我们使用了工厂模式定义了对象,这样就很好的解决了对象无法重用的问题,但是此时又存在了另一个问题,就是我

们无法判断得到的对象的类型了, 如typeof 或者 instanceof来判断类型,仅仅得到一个 Object 类型,所以就推出了

基于构造函数的方式。例如:
function Person(name,age){
this.name = name;
this.age = age;
this.say =function(){
alert("我的名字叫:"+this.name+"我的年龄:"+this.age);
}
}

var p1 = new Person("小石头",38);
var p2 = new Person("鸡棚",28);
p1.say();
p2.say();

alert(p1 instanceof Person);

基于构造函数的定义的方式最大的好处除了对象重复使用外,就是让我们还可以判断它的类型。
此时我们发现基于构造函数的定义对象的方式看似已经很完美了,我们需要的问题它都可以解决了,但是如

果我们仔细的分析这段代码的话,就会发现这样的代码是存在问题的,为什么呢?
我们通过代码分析得知: say 方法在每个对象创建后都存在了一个方法拷贝( 但是我们发现代码在只有调用

时,say 方法才会在堆中创建),这样就增加了内存的消耗了,如果在对象中有大量的方法时,内存的消耗就会高,

这样不行了
解决这个问题的就是我们可以把这个方法放到全局函数,这样就所有的对象指向了一个方法。

function Cat(){};
Cat.prototype.name = "小花";
Cat.prototype.eat = "鱼";
Cat.prototype.say=function(){
alert("我的名字"+this.name+",我的爱好"+this.eat);
}

var p1=new Cat();
p1.say();

var blackCat=new Cat();
blackCat.say();

但是这样写的话,会带来另一个问题,就是方法一点定义为全局函数,那么window 对象就可以调用, 这样

就破坏了对象的封装性。 而且如果有大量的方法,这样写导致整体代码充斥着大量的全局函数,这样将不利于开发。

所以我们急需一种可以完美的解决上述问题的方案,javascript 给我们提供了一种解决这些问题的方案,就是基于原

型的对象创建方案。

function Cat(){};
Cat.prototype.name="猫";
        Cat.prototype.age=2;
Cat.prototype.sex="男";
Cat.prototype.eat=function(){
alert("我的名字叫"+this.name+"我"+this.age+"岁"+this.sex+"我爱吃鱼");
}

var whitecat=new Cat();

whitecat.say();

这样引入原型之后我们可以看到现在的say已经成了Cat对象独有的方法,现在window已经无法访问。这里着重介绍下原型的基本原理:当我们在构建函数的时候Cat的时候就会有一个Cat函数的原型出现,Cat对象直指它的Cat prototype,而Cat prototype中有constructor属性又直指Cat对象本身,这样在写Cat属性的时候相当于把属性全部存入了它的原型当中,而当用构造函数创建出来一个对象之后,那个对象里面又有一个_prop_属性指向原型,当在调用这个对象的某个属性的时候如果这个对象中存入的有这个属性及属性值就会就近原则调用自己本身的属性,如果没有的话就会往原型上面找这个属性然后调用,如果原型上有某个属性及属性值而你在对象中也定义了这个属性及属性值的话也会选择这个对象自身的这个属性来进行调用。然后也可以通过上面的判断方法来判断whitecat是不是指向Cat的原型。。。同样的,用构造函数创造出来的其他对象也跟例子中的那个对象的用法一样。特别要注意的是当我们自己定义原型中已经存在的属性和属性值时,原型中的属性和属性值只是被覆盖了而不是不存在了,这只是一个查找顺序的问题。

接下来要介绍的就是几种常见的检测和删除方式:

1.可以通过以下的方式检测whitecat是不是指向Cat的原型

alert(Cat.prototype.isPrototypeOf(whitecat));

2.可以通过以下的方式检测whitecat的构造器是不是指向Cat

alert(whitecat.constructor==Cat);

3.可以通过以下的方式检测whitecat是不是有自己的某个属性

alert(whitecat.hasOwnProperty("属性名"));

4.可以通过以下的方式来删除我们赋予这个对象的某个属性,但是原型中的属性时不能被删除的。

delete  whitecat.属性名;

    5.如何检测该属性在原型中而不在自己的属性中呢?

function fun(a,obj){
if(!obj.hasOwnProperty(a)){
if(a in obj){
return true;
}
}
return false;
}

这样就可以通过调用这个函数所得到的返回值来检测该对象的某个属性是在原型中还是在自身。

  原型链的继承就是把父类的一个对象赋给子类的原型,这样就实现了子类对父类的继承。例子如下:

function Parent(){
this.pv="parent";
}
Parent.prototype.say=function(){
alert(this.pv);
}

function Son(){
this.sv="son";
}
Son.prototype=new Parent();
Son.prototype.ssay=function(){
alert(this.sv);
}

var s1=new Son();
alert(s1.pv);

s1.say();

从这里我们可以看出现在的子类已经可以调用父类的属性和方法。如果感觉父类的方法不能满足子类的使用的话,就可以把子类的方法名改成和父类的相同,这个叫做方法的覆盖也叫做重写,但是不是重载,JavaScript是弱数据语言类型,没有重载。

但是我们上面的写法也有一些缺陷就是无法在子类中调用父类的构造函数,这样也就无法把子类中的属性赋值给父类。所以我们便引入了基于伪装来实现继承。

function Parent(name){
this.name=name;
}
function Son(name,age){
this.age=age;
Parent.call(this,name);
}
var s1=new Son("父级元素",18);
alert(s1.name);

通过以上的方法我们可以发现通过call方法我们可以实现对父类的属性的修改。同样的,如果想修改很多的父级元素里面的属性的话还可以用apply,可以写成                         Parent.apply(this,[name,age]) ,这样可以多个的修改父类的属性。

但是使用这样方法的话也是有缺陷的,就是子类的原型不会指向父类,所以父类中写在原型中的方法不会被子类继承,所以子类调用不到父类的方法。所以接下来就是终极方案,基于组合来进行继承。

function Parent(name){
this.name=name;
this.friends=['老王','老张']
}
Parent.prototype.say=function(){
alert(this.name+this.age+this.friends);
}

function Son(name,age){
this.age=age;
Parent.apply(this,[name,age]);
}
Son.prototype=new Parent();

Son.prototype.ssay=function(){
alert(this.name+this.age);
}

var s1=new Son("小石头",18);
s1.friends.push('老李');
s1.say();


0 0
原创粉丝点击