论坛首页 Web前端技术论坛

Javascript 继承小结

浏览 1780 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2010-02-26  

对象                                                                                                                                                            

对象是已命名的数据的集合。这些已命名的属性被作为对象的属性来引用。如:person.name

Javascript中的对象可以当作关联数组来使用,如:person[“name”]=”jane”

对象的创建:var obj = new Object();

对象直接量:var obj = {}; var obj = {name:”joye”,age:11}

 

函数                                                                                                                                                            

函数是一个可执行的代码段,只需定义一次,可以多次调用。

function area(x,y){

  return x*y;

}

上面是一个长方形计算面积的函数,通过area(2,3)可以调用它。

Javascript中,函数也是一种数据类型,这意味着:

1、              函数也可以成为某个变量或者是某个对象的属性值。如:var rect = new Object(), rect.area = function(x,y){return x*y;}

2、              函数也可以有属性,如area.counter = 0; function area(x,y){area.counter++; return x*y;}area函数每被调用一次,counter加一

 

                                                                                                                                                              

Javascript中没有类这个概念,但是对象可以拥有属性,而属性的值又可以是函数类型的数据,那么我们可以模拟出类来。

var Person = function(){
  this.name = “jane”; //实例属性
  this.sayHi = function(){alert(“HI,” +this.name)} //实例方法
}
Person.MIN_AGE = 1; //类属性
Person.run = function(){} //类方法
 

上面定义的是一个Person类,其实是一个function对象。

实例属性:是指每个对象都具有的属性,它们各自维护了一份单独的拷贝,比如一个Person类的对象p,name属性就是p的实例属性,可以通过p.name访问,p.name=’kyle’修改。这些操作不会影响别的Person对象的属性值。

实例方法:它与实例属性很相似,只不过它是一个方法,而不是一个数据值。通过p.sayHi()可以调用。实例方法是每个对象都可以调用的方法,但是它并不需要每个对象都维护一份单独的拷贝,方法可以定义在类的原型中,所有的对象共享一个方法。

这里的sayHi()方法在每个实例中都会有一份拷贝,实例方法可以只维持一份拷贝在原型中,这样可以节省空间,在下面介绍了原型之后,在对类进行改进。

类属性:如上的Person.MIN_AGE = 1,它是Person类上的一个属性,跟Person的对象不相关,这个属性只能通过Person类自身来访问

类方法:只能通过Person类自身调用,不能通过Person的实例调用

实例创建                                                                                                                                                    

var p = new Person();  //生成了一个Person类的实例

new Person()分成两部分看,第一部分new创建了一个空的对象,第二部分Person()Person函数的调用,并且把第一部分创建出来的空对象当作是this关键字的值传递。那么这个新生成的对象就会执行Person函数内的代码,就有了属性name,值为”jane”,最后把这个对象设置为p的值。

 

构造函数                                                                                                                                                   

很明显Person函数在创建对象的时候起了初始化对象的作用。它就是创建Person类的构造函数。

构造函数的定义:是初始化一个对象的属性并且专门和New运算符一起使用的一个函数。

 

Prototype                                                                                                                                              

构造过程明白了,在看看new的过程,new 在创建了空对象之后,会给这个对象设置原型,其值是构造函数的prototype属性的值。

所有的函数都有一个prototype属性,当这个函数被定义的时候,prototype属性自动创建和初始化,初始化值是一个对象,这个对象只带有一个属性:constructor,它指回到和原型相关的那个构造函数,此处的Person()。这就是为什么每个对象都有一个constructor属性。

对象没有prototype属性,但是具有对构造函数的prototype的内部引用,也就是说对象可以从构造函数的原型中继承它属性和方法。继承的属性就和对象的常规属性一样,可以使用for..in..来枚举它们。

 

属性读写                                                                                                                                                     

读取属性的值:

当要读取一个对象o的属性p,首先检查o是否有一个名为p的对象,如果没有则查找oprototype中是否有一个名为p的属性。如果在prototype 内定义的实例不能找到属性或函数,它就会在 原型中查找,依此类推。原型继承就是使用这个机制来实现。

设置属性的值:

当要写入一个属性的值时,如果o中并不存在属性p时,Js不会直接去修改prototype中的p属性,因为prototype是一个类所共享的,如果由于一个对象去修改prototype的值,那么别的对象中的p属性值也跟着变化。

修改属性p的值:

Js所做的事情是在o中增加一个新的属性p,并且设置好值,之后在访问op属性时,直接就能在o中访问到p,而不用去访问原型中的p属性。这其实就是o中的p属性隐藏了原型中的p属性。

 

继承                                                                                                                                                          

Javascript中查找属性是通过:对象->原型1,如果原型1也是某个类的对象,则原型1也有一个原型2,那么查找过程就是:对象->原型1->原型2…这样形成一个原型链,Javascript中的继承就是基于这种机制的。

所以要实现继承,只要让子类的原型指向父类的对象。看个例子:

Var Animal = function(){}
Animal.prototype.sleep = function(){
  If(this.type) alert(this.type +”ZZZZ”);
  else alert(“ZZZZ”);
}
Var Dog = function(){
  This.type = “Dog”;
}
Dog.prototype = new Animal();// 把Dog的原型设置为Animal对象
d.sleep();// 提示:”DogZZZZ” 

这样Dog类就继承了 Animal类的sleep方法。在Animal原型中的方法和属性都能够被继承。

 

改进继承                                                                                                                                                      

通过下面代码发现:

alert(d.constructor === Animal) // 值为true

alert(d.constructor === Dog) // 值为false

也就是说Dog对象的构造函数是Animal,而不是Dog,而实际上我们在new Dog()后执行的构造函数是Dog(),这样造成了类关系上的混乱,在修改了子类的prototype时,应该同时修改prototype中的constructor,保证子类自身准确。

改进的继承代码如下:

Var Animal = function(){}
Animal.prototype.sleep = function(){
  If(this.type) alert(this.type +”ZZZZ”);
  else alert(“ZZZZ”);
}
Var Dog = function(){
  This.type = “Dog”;
}
Dog.prototype = new Animal();
Dog.prototype.constructor = Dog; //把Dog新的原型中的constructor指回为原来的constructor.
 

 

一个通用继承方法                                                                                                                                      

以下是一个继承的通用方法,摘自YUI源码:

function extend(subc, superc, overrides) {

    if (!superc||!subc) {
        throw new Error("extend failed, please check that " +
                        "all dependencies are included.");
    }
    var F = function() {};
    F.prototype=superc.prototype;
    subc.prototype=new F();// 修改子类的原型为父类对象
    subc.prototype.constructor=subc;//修改constructor
    subc.superclass=superc.prototype;//当类继承比较简单时,可以设置一个superclass属性,这样需要执行父类的方法时,可以通过superclass来调用
    if (superc.prototype.constructor == Object.prototype.constructor) {
        superc.prototype.constructor=superc;//如果父类的constructor没有指定,则修改为父类自身
    }
 
    if (overrides) { //需要覆盖的方法
        for (var i in overrides) {
            subc.prototype[i]=overrides[i];
        }
    }
}
 

 

 

论坛首页 Web前端技术版

跳转论坛:
Global site tag (gtag.js) - Google Analytics