锁定老帖子 主题:Javascript 继承小结
精华帖 (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的对象,如果没有则查找o的prototype中是否有一个名为p的属性。如果在prototype 内定义的实例不能找到属性或函数,它就会在其 原型中查找,依此类推。原型继承就是使用这个机制来实现。 设置属性的值: 当要写入一个属性的值时,如果o中并不存在属性p时,Js不会直接去修改prototype中的p属性,因为prototype是一个类所共享的,如果由于一个对象去修改prototype的值,那么别的对象中的p属性值也跟着变化。 修改属性p的值: Js所做的事情是在o中增加一个新的属性p,并且设置好值,之后在访问o的p属性时,直接就能在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,保证子类自身准确。 改进的继承代码如下:
一个通用继承方法 以下是一个继承的通用方法,摘自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]; } } }
声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
浏览 1780 次