Как наследовать от класса в javascript?

В PHP/Java можно сделать:

class Sub extends Base
{
}

И автоматически все общедоступные/защищенные методы, свойства, поля и т.д. класса Super становятся частью Sub-класса, которые при необходимости могут быть переопределены.

Что эквивалентно этому в Javascript?

Ответ 1

Я изменил, как я это делаю сейчас, я стараюсь избегать использования функций-конструкторов и их свойства prototype, но мой старый ответ с 2010 года по-прежнему находится внизу. Теперь я предпочитаю Object.create(). Object.create доступен во всех современных браузерах.

Я должен заметить, что Object.create обычно намного медленнее, чем использование new с конструктором функции.

//The prototype is just an object when you use `Object.create()`
var Base = {};

//This is how you create an instance:
var baseInstance = Object.create(Base);

//If you want to inherit from "Base":
var subInstance = Object.create(Object.create(Base));

//Detect if subInstance is an instance of Base:
console.log(Base.isPrototypeOf(subInstance)); //True

jsfiddle

Одним из больших преимуществ использования Object.create является возможность передать аргумент defineProperties, что дает вам значительный контроль над как свойства в классе могут быть доступны и перечислены, и я также использую функции для создания экземпляров, они служат в качестве конструкторов в некотором смысле, поскольку вы можете сделать инициализацию в конце, а не просто возвращать экземпляр.

var Base = {};

function createBase() {
  return Object.create(Base, {
    doSomething: {
       value: function () {
         console.log("Doing something");
       },
    },
  });
}

var Sub = createBase();

function createSub() {
  return Object.create(Sub, {
    doSomethingElse: {
      value: function () {
        console.log("Doing something else");
      },
    },
  }); 
}

var subInstance = createSub();
subInstance.doSomething(); //Logs "Doing something"
subInstance.doSomethingElse(); //Logs "Doing something else"
console.log(Base.isPrototypeOf(subInstance)); //Logs "true"
console.log(Sub.isPrototypeOf(subInstance)); //Logs "true

jsfiddle

Это мой оригинальный ответ от 2010 года:

function Base ( ) {
  this.color = "blue";
}

function Sub ( ) {

}
Sub.prototype = new Base( );
Sub.prototype.showColor = function ( ) {
 console.log( this.color );
}

var instance = new Sub ( );
instance.showColor( ); //"blue"

Ответ 2

В JavaScript у вас нет классов, но вы можете многократно использовать наследование и поведение:

Псевдоклассическое наследование (через прототипирование):

function Super () {
  this.member1 = 'superMember1';
}
Super.prototype.member2 = 'superMember2';

function Sub() {
  this.member3 = 'subMember3';
  //...
}
Sub.prototype = new Super();

Должно использоваться с оператором new:

var subInstance = new Sub();

Функциональное приложение или "цепочка конструктора":

function Super () {
  this.member1 = 'superMember1';
  this.member2 = 'superMember2';
}


function Sub() {
  Super.apply(this, arguments);
  this.member3 = 'subMember3';
}

Этот подход также следует использовать с оператором new:

var subInstance = new Sub();

Различие с первым примером заключается в том, что при apply конструкторе Super для объекта this внутри Sub он добавляет свойства, назначенные this на Super, непосредственно на новом например, например subInstance содержит свойства member1 и member2 непосредственно (subInstance.hasOwnProperty('member1') == true;).

В первом примере эти свойства достигаются через цепочку прототипов, они существуют на внутреннем объекте [[Prototype]].

Паразитарное наследование или силовые конструкторы:

function createSuper() {
  var obj = {
    member1: 'superMember1',
    member2: 'superMember2'
  };

  return obj;
}

function createSub() {
  var obj = createSuper();
  obj.member3 = 'subMember3';
  return obj;
}

Этот подход основан в основном на "усилении объекта", вам не нужно использовать оператор new, и, как видите, ключевое слово this не задействовано.

var subInstance = createSub();

ECMAScript 5th Ed. Object.create:

// Check if native implementation available
if (typeof Object.create !== 'function') {
  Object.create = function (o) {
    function F() {}  // empty constructor
    F.prototype = o; // set base object as prototype
    return new F();  // return empty object with right [[Prototype]]
  };
}

var superInstance = {
  member1: 'superMember1',
  member2: 'superMember2'
};

var subInstance = Object.create(superInstance);
subInstance.member3 = 'subMember3';

Вышеуказанный метод представляет собой прототипный метод наследования, предложенный Crockford.

Объектные экземпляры наследуют от других экземпляров объекта, что он.

Этот метод может быть лучше простого "увеличения объекта", поскольку унаследованные свойства не копируются во все новые экземпляры объектов, так как базовый объект устанавливается как [[Prototype]] расширенного объекта, в приведенном выше примере subInstance содержит физически только свойство member3.

Ответ 3

Для тех, кто достигает этой страницы в 2018 году или после

В последней версии стандарта ECMAScript (ES6) вы можете использовать class de keywork

Обратите внимание, что определение класса не является обычным object следовательно, между членами класса нет запятых. Чтобы создать экземпляр класса, вы должны использовать ключевое слово new. Чтобы наследовать от базового класса, используйте extends:

class Vehicle {
   constructor(name) {
      this.name = name;
      this.kind = 'vehicle';
   }
   getName() {
      return this.name;
   }   
}

// Create an instance
var myVehicle = new Vehicle('rocky');
myVehicle.getName(); // => 'rocky'

Чтобы наследовать от базового класса, используйте extends:

class Car extends Vehicle {
   constructor(name) {
      super(name);
      this.kind = 'car'
   }
}

var myCar = new Car('bumpy');

myCar.getName(); // => 'bumpy'
myCar instanceof Car; // => true
myCar instanceof Vehicle; // => true

Из производного класса вы можете использовать super из любого конструктора или метода для доступа к его базовому классу:

  • Чтобы вызвать родительский конструктор, используйте super().
  • Чтобы вызвать другого участника, используйте, например, super.getName().

Theres больше к использованию классов. Если вы хотите углубиться в тему, я рекомендую " Классы в ECMAScript 6 " доктора Акселя Раушмайера. *

источник

Ответ 4

Ну, в JavaScript нет "наследования классов", есть только "наследование прототипа". Поэтому вы не делаете классный "грузовик", а затем отмечаете его как подкласс "автомобиль". Вместо этого вы создаете объект "Джек" и говорите, что он использует "Джон" в качестве прототипа. Если Джон знает, сколько "4 + 4", то и Джек тоже это знает.

Я предлагаю вам прочитать статью Дугласа Крокфорда о прототипном наследовании здесь: http://javascript.crockford.com/prototypal.html Он также показывает, как вы можете заставить JavaScript выглядеть "похожими" "наследование, как на других языках OO, а затем объясняет, что это на самом деле означает разбиение javaScript таким образом, чтобы оно не предназначалось для использования.

Ответ 5

Я считаю эту цитату наиболее просветляющей:

В сущности, JavaScript "класс" - это просто объект Function, который служит как конструктор плюс прикрепленный объект-прототип. (Источник: Гуру Каца)

Мне нравится использовать конструкторы, а не объекты, поэтому я частично отношусь к методу "псевдоклассического наследования" описанному здесь CMS. Ниже приведен пример множественного наследования с цепочкой прототипов:

// Lifeform "Class" (Constructor function, No prototype)
function Lifeform () {
    this.isLifeform = true;
}

// Animal "Class" (Constructor function + prototype for inheritance)
function Animal () {
    this.isAnimal = true;
}
Animal.prototype = new Lifeform();

// Mammal "Class" (Constructor function + prototype for inheritance)
function Mammal () {
    this.isMammal = true;
}
Mammal.prototype = new Animal();

// Cat "Class" (Constructor function + prototype for inheritance)
function Cat (species) {
    this.isCat = true;
    this.species = species
}
Cat.prototype = new Mammal();

// Make an instance object of the Cat "Class"
var tiger = new Cat("tiger");

console.log(tiger);
// The console outputs a Cat object with all the properties from all "classes"

console.log(tiger.isCat, tiger.isMammal, tiger.isAnimal, tiger.isLifeform);
// Outputs: true true true true

// You can see that all of these "is" properties are available in this object
// We can check to see which properties are really part of the instance object
console.log( "tiger hasOwnProperty: "
    ,tiger.hasOwnProperty("isLifeform") // false
    ,tiger.hasOwnProperty("isAnimal")   // false
    ,tiger.hasOwnProperty("isMammal")   // false
    ,tiger.hasOwnProperty("isCat")      // true
);

// New properties can be added to the prototypes of any
// of the "classes" above and they will be usable by the instance
Lifeform.prototype.A    = 1;
Animal.prototype.B      = 2;
Mammal.prototype.C      = 3;
Cat.prototype.D         = 4;

console.log(tiger.A, tiger.B, tiger.C, tiger.D);
// Console outputs: 1 2 3 4

// Look at the instance object again
console.log(tiger);
// You'll see it now has the "D" property
// The others are accessible but not visible (console issue?)
// In the Chrome console you should be able to drill down the __proto__ chain
// You can also look down the proto chain with Object.getPrototypeOf
// (Equivalent to tiger.__proto__)
console.log( Object.getPrototypeOf(tiger) );  // Mammal 
console.log( Object.getPrototypeOf(Object.getPrototypeOf(tiger)) ); // Animal
// Etc. to get to Lifeform

Вот еще один хороший ресурс из MDN, и вот jsfiddle, чтобы вы могли попробовать его.

Ответ 6

Наследование Javascript немного отличается от Java и PHP, потому что на нем нет классов. Вместо этого он имеет объекты-прототипы, которые предоставляют методы и переменные-члены. Вы можете связать эти прототипы, чтобы обеспечить наследование объектов. Наиболее распространенный образец, который я нашел при исследовании этого вопроса, описан в Mozilla Developer Network. Я обновил свой пример, чтобы включить вызов метода суперкласса и показать журнал в предупреждающем сообщении:

// Shape - superclass
function Shape() {
  this.x = 0;
  this.y = 0;
}

// superclass method
Shape.prototype.move = function(x, y) {
  this.x += x;
  this.y += y;
  log += 'Shape moved.\n';
};

// Rectangle - subclass
function Rectangle() {
  Shape.call(this); // call super constructor.
}

// subclass extends superclass
Rectangle.prototype = Object.create(Shape.prototype);
Rectangle.prototype.constructor = Rectangle;

// Override method
Rectangle.prototype.move = function(x, y) {
  Shape.prototype.move.call(this, x, y); // call superclass method
  log += 'Rectangle moved.\n';
}

var log = "";
var rect = new Rectangle();

log += ('Is rect an instance of Rectangle? ' + (rect instanceof Rectangle) + '\n'); // true
log += ('Is rect an instance of Shape? ' + (rect instanceof Shape) + '\n'); // true
rect.move(1, 1); // Outputs, 'Shape moved.'
alert(log);

Ответ 7

вы не можете (в классическом смысле). Javascript - это прототип языка. Вы увидите, что вы никогда не объявляете "класс" в Javascript; вы просто определяете состояние и методы объекта. Чтобы создать наследование, вы берете некоторый объект и прототип его. Прототип расширен с новой функциональностью.

Ответ 8

Вы можете использовать .inheritWith и .fastClass library. Это быстрее, чем большинство популярных библиотек, а иногда и быстрее, чем родная версия.

Очень проста в использовании:

function Super() {
   this.member1 = "superMember";//instance member
}.define({ //define methods on Super prototype
   method1: function() { console.log('super'); } //prototype member
}.defineStatic({ //define static methods directly on Super function 
   staticMethod1: function() { console.log('static method on Super'); }
});

var Sub = Super.inheritWith(function(base, baseCtor) {
   return {
      constructor: function() {//the Sub constructor that will be returned to variable Sub
         this.member3 = 'subMember3'; //instance member on Sub
         baseCtor.apply(this, arguments);//call base construcor and passing all incoming arguments
      },
      method1: function() { 
         console.log('sub'); 
         base.method1.apply(this, arguments); //call the base class' method1 function
      }
}

Использование

var s = new Sub();
s.method1(); //prints:
//sub 
//super

Ответ 9

function Person(attr){
  this.name = (attr && attr.name)? attr.name : undefined;
  this.birthYear = (attr && attr.birthYear)? attr.birthYear : undefined;

  this.printName = function(){
    console.log(this.name);
  }
  this.printBirthYear = function(){
    console.log(this.birthYear);
  }
  this.print = function(){
    console.log(this.name + '(' +this.birthYear+ ')');
  }
}

function PersonExt(attr){
  Person.call(this, attr);

  this.print = function(){
    console.log(this.name+ '-' + this.birthYear);
  }
  this.newPrint = function(){
    console.log('New method');
  }
}
PersonExt.prototype = new Person();

// Init object and call methods
var p = new Person({name: 'Mr. A', birthYear: 2007});
// Parent method
p.print() // Mr. A(2007)
p.printName() // Mr. A

var pExt = new PersonExt({name: 'Mr. A', birthYear: 2007});
// Overwriten method
pExt.print() // Mr. A-2007
// Extended method
pExt.newPrint() // New method
// Parent method
pExt.printName() // Mr. A

Ответ 10

После прочтения многих сообщений я придумал это решение (jsfiddle здесь). Большую часть времени мне не нужно что-то более сложное

var Class = function(definition) {
    var base = definition.extend || null;
    var construct = definition.construct || definition.extend || function() {};

    var newClass = function() { 
        this._base_ = base;        
        construct.apply(this, arguments);
    }

    if (definition.name) 
        newClass._name_ = definition.name;

    if (definition.extend) {
        var f = function() {}       
        f.prototype = definition.extend.prototype;      
        newClass.prototype = new f();   
        newClass.prototype.constructor = newClass;
        newClass._extend_ = definition.extend;      
        newClass._base_ = definition.extend.prototype;         
    }

    if (definition.statics) 
        for (var n in definition.statics) newClass[n] = definition.statics[n];          

    if (definition.members) 
        for (var n in definition.members) newClass.prototype[n] = definition.members[n];    

    return newClass;
}


var Animal = Class({

    construct: function() {        
    },

    members: {

        speak: function() {
            console.log("nuf said");                        
        },

        isA: function() {        
            return "animal";           
        }        
    }
});


var Dog = Class({  extend: Animal,

    construct: function(name) {  
        this._base_();        
        this.name = name;
    },

    statics: {
        Home: "House",
        Food: "Meat",
        Speak: "Barks"
    },

    members: {
        name: "",

        speak: function() {
            console.log( "ouaf !");         
        },

        isA: function(advice) {
           return advice + " dog -> " + Dog._base_.isA.call(this);           
        }        
    }
});


var Yorkshire = Class({ extend: Dog,

    construct: function(name,gender) {
        this._base_(name);      
        this.gender = gender;
    },

    members: {
        speak: function() {
            console.log( "ouin !");           
        },

        isA: function(advice) {         
           return "yorkshire -> " + Yorkshire._base_.isA.call(this,advice);       
        }        
    }
});


var Bulldog = function() { return _class_ = Class({ extend: Dog,

    construct: function(name) {
        this._base_(name);      
    },

    members: {
        speak: function() {
            console.log( "OUAF !");           
        },

        isA: function(advice) {         
           return "bulldog -> " + _class_._base_.isA.call(this,advice);       
        }        
    }
})}();


var animal = new Animal("Maciste");
console.log(animal.isA());
animal.speak();

var dog = new Dog("Sultan");
console.log(dog.isA("good"));
dog.speak();

var yorkshire = new Yorkshire("Golgoth","Male");
console.log(yorkshire.isA("bad"));
yorkshire.speak();

var bulldog = new Bulldog("Mike");
console.log(bulldog.isA("nice"));
bulldog.speak();

Ответ 11

Благодаря ответу CMS и после долгого простоя с прототипом и Object.create, а что нет, я смог придумать опрятное решение для моего наследования, используя как показано здесь:

var myNamespace = myNamespace || (function() {
    return {

        BaseClass: function(){
            this.someBaseProperty = "someBaseProperty";
            this.someProperty = "BaseClass";
            this.someFunc = null;
        },

        DerivedClass:function(someFunc){
            myNamespace.BaseClass.apply(this, arguments);
            this.someFunc = someFunc;
            this.someProperty = "DerivedClass";
        },

        MoreDerivedClass:function(someFunc){
            myNamespace.DerivedClass.apply(this, arguments);
            this.someFunc = someFunc;
            this.someProperty = "MoreDerivedClass";
        }
    };
})();

Ответ 13

function Base() {
    this.doSomething = function () {
    }
}

function Sub() {
    Base.call(this); // inherit Base method(s) to this instance of Sub
}

var sub = new Sub();
sub.doSomething();

Ответ 14

ES6 классы:

Javascript не имеет классов. Классы в javascript - это просто синтаксическая сборка сахара поверх прототипного шаблона наследования, который есть в javascript. Вы можете использовать class JS для обеспечения наследования прототипов, но важно понимать, что вы все еще используете функции конструктора изнутри.

Эти понятия также применяются, когда вы расширяете класс es6 с помощью ключевого слова extends. Это просто создает дополнительную ссылку в цепочке прототипов. __proto__

Пример:

class Animal {
  makeSound () {
    console.log('animalSound');
  }
}

class Dog extends Animal {
   makeSound () {
    console.log('Woof');
  }
}


console.log(typeof Dog)  // classes in JS are just constructor functions under the hood

const dog = new Dog();

console.log(dog.__proto__ === Dog.prototype);   
// First link in the prototype chain is Dog.prototype

console.log(dog.__proto__.__proto__ === Animal.prototype);  
// Second link in the prototype chain is Animal.prototype
// The extends keyword places Animal in the prototype chain
// Now Dog 'inherits' the makeSound property from Animal

Ответ 15

Вы не можете наследовать из класса в JavaScript, потому что в JavaScript нет классов.