简体   繁体   中英

Why Javascript does not support inheritance by default?

As from OOPS base , I always use inheritance as a powerful tool for code reuse,

Example, if I write a chess program in OOPS and when I implement a is-a relationship as,

Class Piece{
  int teamColor;
  bool isLive;
  Positon pos;
  int Points; 
  .......
  int getTeamColor(){....}
  .......
};

Class Rook extend Piece{  //`is-a`
...... // No getTeamColor() definition here.. because the parent has the definition.
};

Class Pawn extend Piece{  //`is-a`
......// No getTeamColor() definition here.. because the parent has the definition.
};

I could do this with has-a relationship in javascript, but the drawback I am seeing is, I have to redefine every function in the derived class too.

Example : redefinition of getTeamColor() again in every rook,knight,pawn,king.... etc..

     var Pawn = function(teamColor,pos){
     var piece = new Piece(teamColor,pos);
     .......

     this.getTeamColor = function(){        
          return piece.getTeamColor();
    };
    }

My question is, Why javascript doesnot support classical inheritance as a default option?

[Update in 2018] JavaScript now obviously supports inheritance with native language features.

class A { }
class B extends A { }

[/Update]

JavaScript does support inheritance on a prototypal way. What you need here is not classes but the encapsulation of behavior and the ability to override.

function Piece() { }

Piece.prototype.color = "white";
Piece.prototype.getColor = function() { return this.color }
Piece.prototype.move = function() { throw "pure function" };

function Pawn() { }
Pawn.prototype = new Piece();    
Pawn.prototype.move = function() { alert("moved"); }

and now:

var p = new Pawn(); p.color = "black";

> p instanceof Piece

true

 p instanceof Pawn

true

p.getColor()

"black"

p.move()

alert...

This is the basic approach and there are many libraries out there that turn this into something that is familiar for the guys wanting classes - so to say.

For example with JayData you can write the previous in a more encapsulated way (with the bonus of automatic constructor invocation up the chain:

var Piece = $data.Base.extend("Piece", {
  move: function()  {  throw "pure class" } 
});

var Pawn =  Piece.extend("Pawn", {
  move: function() { ... }
});

var p = new Pawn();

Because Javascript is not a class-based object-oriented language , but rather a prototypal one. It's simply a design decision.

Also, Javascript was never really "meant" for all the things we do with it today (from Node.js to ASM.js). The fact that it's still relevant is a testament Brendan Eich and Co. So you may wonder why X or Y was never implemented in JS, but the fact of the matter is that we use JS for things that 20 years ago would have been unforeseeable.

Many good books on various traditional OO languages (including Java, C# and C++) specifically advise against using "implementation inheritance" where possible. Example: Effective Java by Joshua Bloch.

The strange fact is that although implementation inheritance seems to give a regular "shape" to your code, it isn't really helping you solve a problem; more often, it causes problems in the long run.

Those authors tend to give their blessing instead to "interface inheritance" - but in a duck-typed language such as JavaScript there is no need to explicitly declare such inheritance.

And in JS you can "reuse" the same function by simply assigning it as a property on multiple objects. Whatever flavour of inheritance you need, you can conjure it up out of nothing.

JavaScript does not even have real OOP-style classes, you're just able to simulate something similar.

In your example, you can achieve inheritance by doing

var Pawn = function(teamColor, pos) {
    Piece.call(this, teamColor, pos);
}

However, you should typically attach methods to the functions prototype rather than to any new created object. In that case, you can simulate inheritance by setting up a prototype chain, eg, like CoffeeScript does it:

var a, b, _ref,
  __hasProp = {}.hasOwnProperty,
  __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };

a = (function() {
  function a() {}

  return a;

})();

b = (function(_super) {
  __extends(b, _super);

  function b() {
    _ref = b.__super__.constructor.apply(this, arguments);
    return _ref;
  }

  return b;

})(a);

The following code block will "extend" one JavaScript prototype from the other, and ensure that the "instanceof" operator works correctly for the base and derived classes.

From what I can tell, setting TestB's prototype to a new TestA allows for the logical consistancy of the "instanceof" operator.

Passing this to TestA gives the new instance all the desired properties and methods.

Doing it this way is a sort of balance between stylistic desires and pragmatic ones. This will work in most any browser, even Internet Explorer if you're forced to support it. It also helps because having the methods contained in the same block "feels" a lot like your traditional OO syntax.

Also, the main reason JavaScript doesn't support the traditional style of OO is because of its founding philosophy. The founding philosophy is freedom. This freedom is intended to allow developers to engineer their own styles to fit the project's needs.

function TestA(){
  var me = this;

  me.method = function(){
  }
}

function TestB(){
  TestA.call(this);
  var me = this;

  me.otherMethod = function(){
  }
}
TestB.prototype = new TestA();

var test = new TestB();

console.log(test);

console.log(test instanceof TestB);
console.log(test instanceof TestA);

//TestA { method: [Function], otherMethod: [Function] }
//true
//true

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM