代码改变世界

JavaScript学习3:原型和继承

2017-05-21 10:25  tlnshuju  阅读(224)  评论(0编辑  收藏  举报

        原型

        我们创建的每个函数都有一个prototype(原型)属性,这个属性是一个对象,它的用途是包括能够由特定类型的全部实例共享的属性和方法。逻辑上能够这么理解:prototype是通过调用构造函数而创建的那个对象的原型对象。

        为什么要引入原型的概念呢?使用原型的目的。也是他的优点是能够让全部的对象实例共享它所包括的属性和方法。换句话说,就是不必再构造函数中定义对象信息,而是能够直接将这些信息加入到原型中。

        详细怎么用,我们来看代码实例:   

<span style="font-size:18px;">//原型实例
function Person(){}   //声明一个构造函数

Person.prototype.name='Lian';   //在原型里加入属性
Person.prototype.age=100;
Person.prototype.run=function(){    //在原型里加入方法
	return this.name + this.age + '奋斗中……';
};

var person1=new Person();
var person2=new Person();
alert(person1.run==person2.run);   //返回true,说明方法的引用地址是一致的。即两个对象共享了一个方法</span>

        为了更好的理解构造函数的声明方式和原型模式的声明方式的差别,我找了两张图分享给大家。帮助大家理解:

        

        我们从图中能够看到,在原型模式声明中。多了两个属性,这两个属性都是创建对象时自己主动生成的。_proto_属性是实例指向原型对象的一个指针,它的作用就是指向构造函数的原型属性constructor。通过这两个属性,就能够訪问到原型里的属相和方法了。

        看到这里你会认为奇怪。上面代码实例中的构造函数的函数体中什么也没有。才干訪问到原型对象里的值,假设函数体中有属性或者方法呢?这里就要涉及一个原型模式运行流程的问题了:是先去查找构造函数实例里面的属性和方法,假设有。立马返回,若没有,则去它的原型对象中找。若有,则返回。

        使用原型模式创建对象也有其缺点,那就是它省略了构造函数传參初始化这一过程。带来的缺点就是初始化的值都是一样的。可是这恰恰是它最大的长处,那就是共享。

        继承

        继承是面向对象中的一个核心概念,在比較正统的面向对象的语言中一般都会採用两种方式实现继承:一个是接口实现,一个是类继承。而我们的JavaScript仅仅支持继承。而不支持接口实现,继承是怎样实现的,这里要引入原型链的概念了。什么是原形链。我们看一段代码就会知道。

<span style="font-size:18px;">//继承实例
function A(){
	this.name ='Lian';
}

function B(){
	this.age=100;
}

function C(){
	this.address='中国';
}
B.prototype.age =200;
B.prototype =new A();  //B继承了A

C.prototype =new B();  //C又继承了B

var c=new C();
alert(c.name+' '+ c.age);  //C具有了A和B的属性</span>

        在JavaScript中,被继承的函数称为超类型(也就是面向对象中说的父类或者说是基类),继承的函数称为子类型(即子类或者派生类)。继承有优点。可是也有其自己的问题,比方字面量重写原型会中断关系,使用引用类型的原型,而且子类型无法给超类型传递參数。

        综合考虑,我们使用原形链加上构造函数,这样产生了组合继承。      

<span style="font-size:18px;">//组合继承
function Box(age){
	this.name='Lee';
	this.age=age;
}

Box.prototype.run=function(){
	return this.name +this.age;
};

function Desk(age ){
	Box.call(this,age);   //对象冒充,给超类型传參
}

Desk.prototype =new Box();   //原形链继承

var desk =new Desk(100);
alert (desk.run());   //显然Desk继承了Box的run方法</span>

        组合继承是JavaScript最经常使用的继承方式,可是,组合继承也有一点问题。那就是超类型在使用过程中会被调用两次。一次是创建子类型的时候。一次是在子类型构造函数的内部。

这样会带来性能上的开销,怎样解决?留给读者去思考……