JavaScript面向对象,Web前端之家

上文提到我们不会单独使用基于函数伪造的方式实现继承,而是会使用基于原型链和函数伪装组合的方式实现继承。这种继承方式也叫伪经典继承,它的思想是使用原型链实现对原型属性和方法的继承,而通过借用构造函数来实现对实例属性的继承。这样,既通过在原型上定义方法实现了函数的复用,又能够保证每个实例都有它自己的属性。

由于基于原型链实现继承的方式存在一些缺点,所以人们采用了另外一种方式来实现继承——基于函数伪造的方式实现继承。这个技术的思想是在子类构造函数的内部调用父类的构造函数。

来看下面的例子,我们先列出基于原型链和函数伪装组合的方式实现继承完整的代码,然后再对代码中的每一步做内存模型分析。

基于函数伪造的方式实现继承的实现方式

// 第一部分function Parent{ this.color = ["red","blue"]; this.name = name;}Parent.prototype.talk = function(){ alert(this.name+"["+this.color+"]");}// 第二部分function Child{ //函数伪造继承 Parent.call; this.age = age;}// 原型链继承Child.prototype = new Parent();Child.prototype.say = function(){ alert(this.name+","+this.color);}//第三部分var c1 = new Child;c1.color.push;c1.say(); // 输出:Leon[red,blue,green]var c2 = new Child;c2.say(); // 输出:Ada[red,blue]

因为在JavaScript中,函数是在特定环境中执行代码的对象,所以我们可以使用call()apply()方法来在子类对象上执行父类对象的构造函数。来看下面的例子:

我们先来看代码中的第一部分,在这段代码中,我们创建了父类Parent,并为它添加了2个属性。然后在Parent的原型中添加一个方法talk()。此时的内存模型如下图所示:

/* 创建父类 */function Parent(){ this.color = ["red","blue"];}/* 创建子类 */function Child(){ // 继承父类的属性 Parent.call;}

接下来在代码的第二部分,我们创建了子类Child,在子类Child内部使用函数伪造的方式继承父类的属性。然后通过原型链继承的方式使子类的原型指向父类对象,并在新的子类原型上添加了一个say()方法。此时的内存模型如下图所示:

在上面的代码中,我们首先创建了一个父类Parent,然后创建一个子类Child,并在子类的内部使用Parent.call;来完成继承。

最后,在第三部分代码中,我们分别创建了两个子类对象c1和c2。然后为c1对象的color属性添加一个新的颜色,并调用c1的say()方法,对于c2同样也调用它的say()方法。此时的内存模型如下图所示:

在函数的属性一文中,我们已经介绍了call()apply()方法,这两个方法的作用是在特定的作用域中调用函数,也就是说这两个方法可以通过函数名称来调用函数。在这里我们在Child的内部使用Parent.call;来完成继承,这句话的意思是在子类中调用父类的构造函数,此时的this指的是Child对象(在Child中的this应该是执行Child的对象),所以就等于在Child中有了一句this.color = ["red","blue"];,也就是等于在Child中有了this.color属性,这样也就变相的完成了继承。

我们可以看到,为对象的引用类型属性设置值是在它自己的空间中完成的,这样每一个对象都有它自己独立的属性,互不干扰。

我们可以通过下面的方法来进行验证:

以上就是基于原型链和函数伪装组合的方式实现继承的完整代码和内存模型分析,也是我们在JavaScript中最常用的一种实现继承的方式。

var c1 = new Child(); //创建子类对象c1c1.color.push; //为c1添加新的颜色console.info; //控制台输出:red,blue,Greenvar c2 = new Child(); //创建子类对象c2console.info; //控制台输出:red,blue

返回javascript教程主目录>>

在上面的代码中,我们创建了子类对象c1,并为它添加新的颜色”Green“,所以会在控制台中输出:”red,blue,Green”。然后我们又创建了对象c2,因为没有为它添加新的颜色,所以它只会在控制台中输出继承自父类的颜色:”red,blue”。

每调用一次new Child就等于执行了一次对象属性的设定,此时,每个对象的空间中都有color属性,而不会在原型中存在,所以color不会被共享。这样就解决了原型链继承中引用类型变量存在的问题。

子类构造函数

You can leave a response, or trackback from your own site.

Leave a Reply

网站地图xml地图