1.js的面向对象思想
在之前的学习中,我们已经涉及了对象、方法和属性。同时,js中没有类的概念,但是可以用构造器函数来实现相同的功能。对于封装,对象本身就包括数据以及与这些数据相关的方法。对于聚合,一个对象中也包含其他对象。
2.原型链
首先,先来看一下通过原型来实现继承关系链。 js中的每一个函数都有一个指向某一对象的prototype属性,该函数被new操作符调用时会创建并返回一个对象,并且该对象中会有一个指向其原型对象的秘密链接。通过该秘密链接,我们就可以在新建的对象中调用相关原型对象的方法和属性。 而原型对象自身也有具有对象固有的普遍特征,因此本身也包含了指向原型的链接。 首先来定义三个构造器函数:
function Shape(){
this.name = 'Shape';
this.toString = function(){
return this.name;
};
}
function TwoDShape(){
this.name = '2D shape';
}
function Triangle(side, height){
this.name = 'Triangle';
this.side = side;
this.height = height;
this.getArea = function(){
return this.side * this.height / 2;
};
}
TwoDshape.prototype = new Shape();
Triangle.prototype = new TwoDshape();
在这里,我们将对象直接创建TwoDshape对象的prototype属性中,并没有去扩展这些对象的原有原型,也就是说,用构造器Shape()(通过new操作符)另建了一个新的对象,然后用它去覆盖TwoDShape构造器的prototype属性。Triangle对象也一样,它的prototype属性是由构造器TwoDShape()负责重建的。js是一种完全依靠对象的语言,其中没有类的概念。因此我们需要直接用new Shape()构造器。另外这也确保了在继承实现之后,我们对Shape()所进行的任何修改、重写甚至删除,都不会对TwoDShape()产生影响,因为我们所继承的只是由该构造器所建的一个实体。 当我们对对象constructor属性产生一定的副作用。所以,在我们完成相关的继承关系设定后,对这些对象的constructor属性产生一定的副作用。所以,在我们完成相关的继承关系设定后,应该对这些对象的constructor属性进行相应的重置。
TwoDShape.prototype.constructor = TwoDshape;
Triangle.prototype.constructor = Triangle;
先创建一个Triangle对象,然后调用它的getArea()方法:
>var my = new Triangle(5, 10);
>my.getArea();
>25
尽管my对象中并没有属于自己的toString()方法,但我们依然可以调用它所继承的toString()方法。虽然这里调用的是一个继承方法,但this所指向的依然是my对象。
>my.toString()
>"Triangle"
这个过程发生了这几件事:
- 首先,会遍历my对象中所有的属性,但没有找到toString()的方法。
- 接着再去my.__proto__所指向的对象,该对象是在继承关系构建过程中由new TwoDShape()所创建的。
- 显然,js引擎在遍历TwoDshape实体的过程中依然不会找的toString()方法。然后,它又会继续检查该实体的__proto__属性。此时,该属性所指向的实体是由new Shape()所创建的。
- 终于,在new Shape()所创建的实体中找到了toString()方法。
- 最后,该方法就会在my对象中被调用,并且其this也指向了my。
|