Funtion about Override Inheritance in javascript

  Original Link:http://www.sitepoint.com/blogs/2006/01/17/javascript-inheritance/ 

  Searching Google for “Javascript Inheritance” returns some interesting but, IMO, also frustrating results such as Douglas Crockford’s various takes in Classical Inheritance in JavaScript or Kevin Lindsey’s approach, the former not really providing a clear answer while the latter relies on the convention of attaching a “superclass” property to your objects and effectively requires glueing your objects together for each instance you create.

   Meanwhile libraries like prototype and MochKit have evolved their own conventions and strategies which you may or not may not appreciate. I’m grumpy in each case . prototype, despite having some very cool code in it, extends built-in Javascript types like Object which I don’t appreciate – makes me nervous about mixing in other Javascript libraries from other sources. Meanwhile looking at MochKit (which may be the best AJAX implementation out there, having made good reference to twisted) suffers from the kind of smartness summarized here, when it comes to it’s “Base”.

An Alternative

  There is another way which probably gives you most of what you expect if you’re coming from a language like Java (ooops – can’t seem to stop it ;)). This is thanks to Troels Knak-Nielsen (author of indite – the realtime validating wysiwyg widget) who told me about it a long time ago on the JPSpan mailing list here.

  function copyPrototype(descendant, parent) {  
  var sConstructor = parent.toString();  
  var aMatch = sConstructor.match( /\s*function (.*)\(/ );  
  if ( aMatch != null ) { descendant.prototype[aMatch[1]] = parent; }  
  for (var m in parent.prototype) {  
    descendant.prototype[m] = parent.prototype[m];  
  }  
 };

Note: above code updated after initial post re this comment

  At first glance, with that regex, it looks like a hack but if you allow it to sink in (which has taken me more than a year), you realise that it isn’t. It’s worth bearing in mind what Troels had to say about it;

First off – I fully understand and agree to the point of not extending language functionality. That said I think the point in relation to javascript and inheritance is often misunderstood. It is central to javascript that it is a “typeless objectoriented language”. This goes for ECMAscript3.0 all the same. Where people most often get it wrong is when they mistake prototypes for classes – they are not.

In a typed OO-language the objects code lies with the class – objects are just instances. In js, the code lies in the object. Therefore, the object is not tied to the prototype. It is ok in js to manipulate the prototype runtime, even after objects has been instantiated. Consider doing that with a typed language.

  Anyway. I have been working a lot with js recently, and found that one-level inheritance is simple enough using prototypes, but further inheritance cause trouble. I guess you came to the same conclusion with JPSpan. My first googling on the subject turned up a lot of wierd hacks, that I don’t appreciate. I eventually invented a solution witch I use, and witch I’m very happy with. It may look as a hack, but it works so well, that I kind of forgive it for that.

To defend myself further I’ll point out that it’s not a language extension, if you just understand what it does. It’s merely a utility that extends a prototype – Which should not be confused with class inheritance (though the result is the same).

It’s easiest to see Troels point by trying it…

Basic

Inheritance

The way you’d expect…

 function Animal() {  
  this.species = "animal";  
 };  
 Animal.prototype.category = function() {  
   alert(this.species);  
 };  
 function Dog() {  
  // Call the parent constructor to setup  
  // the parent object properties...  
 this.Animal();  
 };  
 // Dog "inherits" from Animal  
 copyPrototype(Dog, Animal);  
 var d = new Dog();  
 d.category(); 

…and I get the alert “animal”

Another spin on that, this time without calling the parent constructor…

 function Animal() {  
  this.species = "animal";  
 };  
 Animal.prototype.category = function() {  
  alert(this.species);  
 };  
 function Dog() {  
  // No call to parent constructor  
  this.species = "canine";  
 };  
 // Dog "inherits" from Animal  
 copyPrototype(Dog, Animal);  
 var d = new Dog();  
 d.category(); 

This time the alert reads “canine”.

Many generations

Often a problem with different approaches to Javascript inheritance, here’s how Troels approach deals with it;

 function Animal() {  
  this.species = "animal";  
 };  
 Animal.prototype.category = function() {  
  alert(this.species);  
 };  
 function Dog() {  
  this.Animal();  
  this.species += ":dog";  
 };  
 // Dog "inherits" from Animal  
 copyPrototype(Dog, Animal);  
 function Poodle() {  
  this.Dog();  
  this.species += ":poodle";  
 };  
 // Poodle "inherits" from Dog  
 copyPrototype(Poodle, Dog);  
 var p = new Poodle();  
 p.category(); 

…alerts: “animal:dog:poodle”

Overriding Parent Methods

By default this approach simply replaces methods. That means you need to make sure you call copyPrototype before assigning any methods to the subclass prototype, otherwise the parent methods will override the child methods;

 function Animal() {  
  this.species = "animal";  
 };  
 Animal.prototype.category = function() {  
  alert(this.species);  
 };  
 function Dog() {  
  this.Animal();  
  this.species += ":canine";  
 };  
 // Dog "inherits" from Animal  
 copyPrototype(Dog, Animal);  
 // Override parent method _after_ calling copyPrototype  
 Dog.prototype.category = function() {  
 alert(this.species.toUpperCase())        
}; 

… displays “ANIMAL:CANINE”

It’s also possible, although slightly painful, to call a parent method which has been overridden, with help from apply. Modifying the above Dog.prototype.category method demonstrates this;

 Dog.prototype.category = function() {  
  // Call overridden parent method...  
  Animal.prototype.category.apply(this);  
  alert(this.species.toUpperCase())  
 }; 

…which results in two alerts. If you needed to pass on method parameters, you’d need to pass the arguments array as the second argument to apply().

Mixins

MixIns (basically multiple inheritance) also works in a fairly predictable fashion;

 function Animal() {  
  this.species = "animal";  
 };  
 Animal.prototype.category = function() {  
  alert(this.species);  
 };  
 function Quadruped() {};  
  Quadruped.prototype.run = function() {  
  alert('Running...');  
 }  
 function Dog() {  
  this.Animal();  
  this.species += ":canine";  
 };  
 // Dog "inherits" from Animal  
 copyPrototype(Dog, Animal);  
 // Dog "inherits" from Quadruped  
 copyPrototype(Dog, Quadruped);  
 var d = new Dog();  
 d.category();  
 d.run(); 

…two alerts: “animal:canine” and “Running…”

Cautions

Two particular warnings with this approach…

1. When you call copyPrototype matters, as already mentioned. In practice it means you’re best off calling it immediately after declaring a child constructor.

2. Do not declare a toString method for the parent class Function object as this may break the regular expression in copyPrototype. You can still modify a parent prototype without doing any harm though. In other words this will break copyPrototype;

In Summary

Of all the approaches I’ve seen, to me this has become the most convincing – the best way to keep your code DRY without having to modify core Javascript types and introduce strange side effects. It’s also only 8 lines of code, so doesn’t cost much. Credit to Troels for sublime lateral thinking. 

转载于:https://www.cnblogs.com/normalheart/archive/2010/08/31/1813784.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值