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



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



class Sub extends Base
{
}


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



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

571   15  

15 ответов:

Я изменил, как я делаю это сейчас, я стараюсь избегать использования функций конструктора и их 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

одно из больших преимуществ использования объекта.создать будучи в состоянии пройти в 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"

в 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 the Super конструктор this объект внутри Sub, он добавляет свойства, назначенные this on 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 5-е изд. 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';

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

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

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

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

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

обратите внимание, что определение класса не является регулярным 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().

там больше к использованию классов. Если вы хотите копнуть глубже в эту тему, рекомендую "классы в ECMAScript 6 " доктор Аксель Rauschmayer.*

источник

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

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

Я нахожу эту цитату наиболее поучительной:

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

Мне нравится использовать конструкторы, а не объекты, поэтому я неравнодушен к методу "псевдоклассического наследования" описано здесь 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 так что вы можете попробовать его.

наследование 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);

лично я нахожу наследование в Javascript неудобным, но это лучшая версия, которую я нашел.

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

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

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

function Super() {
   this.member1 = "superMember";//instance member
}.define({ //define methods on Super's 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
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

прочитав много постов, я придумал это решение (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();

благодаря ответу CMS и после возиться некоторое время с прототипом и объектом.создайте, а что нет, я смог придумать аккуратное решение для моего наследования, используя apply, как показано здесь:

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";
        }
    };
})();

от ES2015, это именно то, как вы делаете наследование в JavaScript

class Sub extends Base {

}
  1. https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Classes
  2. http://exploringjs.com/es6/ch_classes.html
function Base() {
    this.doSomething = function () {
    }
}

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

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

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

на ES6 классы:

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

эти понятия также применяются, когда вы расширяетесь от '' С помощью ключевого слова 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

Comments

    Ничего не найдено.