Javascript-форум (https://javascript.ru/forum/)
-   Общие вопросы Javascript (https://javascript.ru/forum/misc/)
-   -   Виртуальный класс а-ля Си Плас Плас (https://javascript.ru/forum/misc/51128-virtualnyjj-klass-lya-si-plas-plas.html)

Voronar 24.10.2014 21:33

Виртуальный класс а-ля Си Плас Плас
 
Здравствуйте хочу реализовать сабж в JS.
Есть вот такой код:
function Interface() {};
Interface.prototype.p1 = "property1";

function Class() {};
Class.prototype = new Interface();

var obj = new Class();
console.log(obj.p1);


Так всё работает как надо, но у меня есть один вопрос. Почему в свойстве prototype "класса наследника" Class нужно указывать именно экземпляр функции-конструктора Interface, а не саму функцию-конструктор. А то получается, что нужно сначала потратить память для создания объекта, а потом уже только я получаю возможность "наследования". А если я буду наследовать 20 "классов"?

#1 В принципе, можно использовать один созданный объект для этих 20 "классов", но мне всё равно хочется узнать, как можно обойтись без создания экземпляра родительской функции-конструктора..

terminator-101 24.10.2014 22:32

Цитата:

Сообщение от Voronar
А то получается, что нужно сначала потратить память для создания объекта, а потом уже только я получаю возможность "наследования".

Короче, за пвмять особо не беспокойся. Так как на твой объект никто не ссылается, его загребет GC, но если это тебя беспокоит, можешь сделать вот так
function Interface() {};
Interface.prototype.p1 = "property1";
 
function Class() {};
Class.prototype = Interface.prototype
 
var obj = new Class();
alert(obj.p1);

Толко это не прокатит, если ты хочешь сделать Class реально наследником Interface, а не только наследовать от его прототипа. Но в твоем случае и так сойдет. То что ты написал, имеет смысл, только если
function Interface() {this.a=1; this.b=2};
Interface.prototype.p1 = "property1";
 
function Class() {};
Class.prototype = new Interface
 
var obj = new Class();
alert([obj.p1, obj.a, obj.b]);

Voronar 24.10.2014 22:40

Да, я буду расширять, обязательно.
Так как ты указал я делал. Проблема возникает, когда я хочу сделать вот так:
Class.prototype.p1 = "new value";

В этом случае свойство меняется у базового класса Interface, а мне нужно поменять прототип c одноимённым свойством только для Class.

terminator-101 24.10.2014 22:46

Цитата:

Сообщение от Voronar
В этом случае свойство меняется у базового класса Interface, а мне нужно поменять прототип c одноимённым свойством только для Class.

Ну так указывай тогда этот прототип только для Class, нахрен ты на Interface его вешаешь?

terminator-101 24.10.2014 22:58

Voronar,
Короче, Class не обязан наследовать прототип Interface, он может иметь и свой собственный прототип. Тогда его экземпляры будут лазить за этим свойством именно в прототип родителя. А вообще, непонятны твои цели, что именно ты хочешь реализовать. Может в твоей задаче вообще классы не нужны. В JS Можно наследовать и напрямую от объектов. В любом случае, реализовать можно любую модель, как 2 пальца об асфальт.

Voronar 24.10.2014 23:03

В "классе" Interface я хочу сделать чистые виртуальные функции, то есть аналог С++ ООП-интерфейса.
Когда я буду реализовывать эти функции в Class1, Class2 и Classn, то функции прототипа Interface будут каждый раз перетираться. А я хочу иметь реализации функций из Interface для каждого экземпляра Class1, Class2 и Classn, и чтобы у меня имелось только одно объявления функции для каждого класса.
Можно описать эти классы по отдельности, но я хочу их наследовать от базового виртуального класса Interface.

Voronar 24.10.2014 23:13

function Interface() {};
Interface.prototype.fd = "file descriptor";
Interface.prototype.open = "virtual function";
Interface.prototype.close = "virtual function";


function Class1() {};
function Class2() {};
Class1.prototype = new Interface();
Class2.prototype = new Interface();

Class1.prototype.open = function()
{
    alert("open1");
};
Class1.prototype.close = function()
{
    alert("close1");
};

Class2.prototype.open = function()
{
    alert("open2");
};
Class2.prototype.close = function()
{
    alert("close2");
};

var obj1 = new Class1();
var obj2 = new Class2();
obj1.open();
obj2.open();


Работает так, как я хочу, но в итоге мне нужно создавать для каждого наследника новый экземпляр Interface, а я хочу обойтись минимальными затратами памяти.

terminator-101 24.10.2014 23:19

Цитата:

Сообщение от Voronar (Сообщение 337421)
В "классе" Interface я хочу сделать чистые виртуальные функции, то есть аналог С++ ООП-интерфейса.
Когда я буду реализовывать эти функции в Class1, Class2 и Classn, то функции прототипа Interface будут каждый раз перетираться. А я хочу иметь реализации функций из Interface для каждого экземпляра Class1, Class2 и Classn, и чтобы у меня имелось только одно объявления функции для каждого класса.
Можно описать эти классы по отдельности, но я хочу их наследовать от базового виртуального класса Interface.

Не знаю, что там в ++, но похоже на это.
function Interface() {}; 
Interface.prototype.p1 = "property1";
 
function Class(prop) {if(prop) this.p1=prop};
Class.prototype = new Interface
 
o1=new Class();
o2=new Class("foo")
alert([o1.p1, o2.p1]);

Voronar 24.10.2014 23:31

Цитата:

Сообщение от terminator-101 (Сообщение 337423)
Не знаю, что там в ++, но похоже на это.
function Interface() {}; 
Interface.prototype.p1 = "property1";
 
function Class(prop) {if(prop) this.p1=prop};
Class.prototype = new Interface
 
o1=new Class();
o2=new Class("foo")
alert([o1.p1, o2.p1]);

Может я ошибаюсь, но мне кажется, что в этом случае функция(объект), имя которой ты передаёшь как параметр конструктора, будет создаваться для каждого экземпляра (так как ты используешь this), а это слишком затратно.
Я описал своё видение в примере, приведённом мной выше.
Из моего примера видно, что для любого экземпляра Class1 или Class2, этот экземпляр будет иметь только одну реализацию функции в прототипе. То есть получается, что по-любому для каждого наследника нужно создавать экземпляр Interface.

kostyanet 25.10.2014 03:23

Цитата:

Сообщение от Voronar
А если я буду наследовать 20 "классов"?

Кавычки поставили позже, на 2 слова раньше надо.

Что вы задумали то не имеет смысла. Пишите на этом языке, а не на том, который вы лучше знаете. В штатах люди живут годами после переезда и не говорят по-английски, так и вы собираетесь писать на js как в тылу врага.

Erolast 25.10.2014 06:07

Цитата:

Сообщение от Voronar (Сообщение 337406)
Здравствуйте хочу реализовать сабж в JS.
Есть вот такой код:
function Interface() {};
Interface.prototype.p1 = "property1";

function Class() {};
Class.prototype = new Interface();

var obj = new Class();
console.log(obj.p1);


Так всё работает как надо, но у меня есть один вопрос. Почему в свойстве prototype "класса наследника" Class нужно указывать именно экземпляр функции-конструктора Interface, а не саму функцию-конструктор. А то получается, что нужно сначала потратить память для создания объекта, а потом уже только я получаю возможность "наследования". А если я буду наследовать 20 "классов"?

А это и не правильно. В таком случае наследующий класс не сможет иметь своих методов. Надо, чтобы .prototype.__proto__ наследующего класса было равно .prototype наследуемого. Реализуется как-то так:
function inherits(Child, Parent) {
  Child.prototype = Object.create(Parent.prototype, {
    constructor: {
      writable: true,
      configurable: true,
      enumerable: false
    }
  })
}


Вообще я бы посоветовал смотреть в сторону ES6, если хочется нормального ООП. Это еще неутвержденная спецификация Javascript, пока что на ней можно писать через компиляцию (спасибо kobezzza за ссылку).
class Parent {
  constructor() {

  }
  method() {

  }
}
class Child extends Parent {
  static staticMethod() {

  }
  get getter() {

  }
}

terminator-101 25.10.2014 12:55

Цитата:

Сообщение от Voronar
будет создаваться для каждого экземпляра (так как ты используешь this), а это слишком затратно.

Да, ступил на ночь глядя, бошка не варила. Вот этот вариант не пойдет?
Interface=function(init){
   var o={}
   var base={
      open: function(){console.log("virtual open")},
      close: function(){console.log("virtual close")}
   }
   if(init){
      o.open=init.open||base.open
      o.close=init.close||base.close
   }else{
      o.open=base.open
      o.close=base.close
   }
   return function(){return Object.create(o)}
}

Class1=Interface({open: function(){console.log("just open")}})
Class2=Interface({close: function(){console.log("just close")}})
Class3=Interface()

o1=Class1()
o2=Class2()
o3=Class3()

o1.open(); o1.close(); o2.open(); o2.close(); o3.open(); o3.close()

//  just open
//  virtual close
//  virtual open
//  just close
//  virtual open
//  virtual close

terminator-101 25.10.2014 14:12

Цитата:

Сообщение от Erolast
В таком случае наследующий класс не сможет иметь своих методов

Сможет он их иметь, не надо п*ть, когда не знаешь. Впрочем, тебе не впервой.
function Interface() {};
Interface.prototype.p1 = "property1";
function Class() {this.a=1; this.b=function(){alert(this.a)}};
Class.prototype = new Interface();
var obj = new Class();
alert([obj.p1, obj.a]);
obj.b()

Erolast 25.10.2014 14:45

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

Кстати, с каких это пор ты стал употреблять ; и var?

terminator-101 25.10.2014 14:50

Цитата:

Сообщение от Erolast
Реализуется как-то так:

И что ты написало? Это все равно, что
function Interface() {};
Interface.prototype.p1 = "property1";
 
function Class() {};
Class.prototype = Interface.prototype;
 
var obj = new Class();

Обсуждали уже в начале топика, ему надо чтобы изменение дочернего класса не влияло на Interface, идиот. А ты написал то же самое, только мудреным синтаксисом (чтоб никто не догадался опять?)

function inherits(Child, Parent) {
  Child.prototype = Object.create(Parent.prototype, {
    constructor: {
      writable: true,
      configurable: true,
      enumerable: false
    }
  })
}


O=function(){}
O.prototype={a:1}
Child=function(){}
inherits(Child, O)
o=new Child
console.log(o.a)
Child.prototype.a=10
console.log(o.a)
o1=new Child
console.log(o1.a)

//  1
//  10
//  10

Не лезь в треды, где мужики разговаривают, пиши жеквери, это самое твое.

terminator-101 25.10.2014 14:52

Цитата:

Сообщение от Erolast
При этом каждый новый инстанс будет иметь свою собственную пачку методов, что в большинстве случаев нецелесообразно и приводит к перерасходу памяти

Это не имеет никакого отношения к делу. Как там быдло что называет, никого не волнует. С точки зрения работы кода, это именно то, о чем ты кукарекал. А свою жаба-терминологию держи при себе.
Цитата:

Сообщение от Erolast
к перерасходу памяти

Это можно легко решить, но я распинаться перед тобой не буду, один х не поймшь

terminator-101 25.10.2014 14:59

Цитата:

Сообщение от Erolast
Кстати, с каких это пор ты стал употреблять ; и var?

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

terminator-101 25.10.2014 15:03

Цитата:

Сообщение от Erolast
Кстати, с каких это пор ты стал употреблять ; и var?

Ты про какой, вообще кусок говоришь? Если про этот, http://javascript.ru/forum/showthrea...515#post337475, то там все по делу употреблено, ущерб, там без них код не отработает. Я что говорил, что нигде употреблять не надо? Разупорись.

Erolast 25.10.2014 15:03

Цитата:

Обсуждали уже в начале топика, ему надо чтобы изменение дочернего класса не влияло на Interface, идиот.
А при такой реализации оно и не будет влиять, идиот.
Цитата:

ты написал то же самое, только мудреным синтаксисом (чтоб никто не догадался опять?)
Нет, не то же.
Цитата:

Не лезь в треды, где мужики разговаривают, пиши жеквери, это самое твое.

Это не имеет никакого отношения к делу. Как там быдло что называет, никого не волнует. С точки зрения работы кода, это именно то, о чем ты кукарекал. А свою жаба-терминологию держи при себе.

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

terminator-101 25.10.2014 15:12

Цитата:

Сообщение от Erolast
А при такой реализации оно и не будет влиять, идиот.

Ты мудило кнокпу run нажми хотя бы для приличия

Erolast 25.10.2014 15:17

И не буду, пример неверен. Надо так:
function inherits(Child, Parent) {
  Child.prototype = Object.create(Parent.prototype, {
    constructor: {
      value: Child,
      writable: true,
      configurable: true,
      enumerable: false
    }
  })
}

function Interface(){};
function Class(){};

inherits(Class, Interface);

Interface.prototype.someValue = 1;
Class.prototype.someValue = 2;

alert((new Interface()).someValue);
alert((new Class()).someValue);

terminator-101 25.10.2014 15:20

Erolast,
Поправь код, у тебя ошибка там. Как поправишь, будем дальше смотреть.

Erolast 25.10.2014 15:52

Пардон, поправил.

terminator-101 25.10.2014 15:59

Erolast,
Че то я не догоняю, до конца, че там происходит. Ща некогда, потом подумаю. Отпишусь завтра.

Erolast 25.10.2014 18:10

Сначала
Цитата:

не надо п*ть, когда не знаешь. Впрочем, тебе не впервой.

пиши жеквери, это самое твое.

я распинаться перед тобой не буду, один х не поймшь
, а потом "что-то не догоняю, что происходит"? Найс.

Sweet 25.10.2014 19:10

Цитата:

Сообщение от Erolast
а потом "что-то не догоняю, что происходит"? Найс.

Ага, тоже доставило. Это ж классика. Что там думать?:)

Voronar 25.10.2014 19:33

Цитата:

Сообщение от Erolast (Сообщение 337528)
И не буду, пример неверен. Надо так:
function inherits(Child, Parent) {
  Child.prototype = Object.create(Parent.prototype, {
    constructor: {
      value: Child,
      writable: true,
      configurable: true,
      enumerable: false
    }
  })
}

function Interface(){};
function Class(){};

inherits(Class, Interface);

Interface.prototype.someValue = 1;
Class.prototype.someValue = 2;

alert((new Interface()).someValue);
alert((new Class()).someValue);

А почему вместо Object.Create() не использовать просто new? Или тут в качестве параметра descriptors задаётся что-то жизненно важное?

P.S. Ну тут без меня началось... Я не встреваю в междусобойчик.

Erolast 25.10.2014 19:37

Цитата:

А почему вместо Object.Create() не использовать просто new? Или тут в качестве параметра descriptors задаётся что-то жизненно важное?
Ты имеешь в виду, почему не "new Parent()"? Потому что, во-первых, нам не нужно вызывать конструктор, во-вторых, Class.prototype.constructor должен быть равен самому классу, а при создании через new он будет равен родителю.

Но ты таки присмотрись к ES6.

Voronar 25.10.2014 19:51

Цитата:

Сообщение от Erolast (Сообщение 337557)
Ты имеешь в виду, почему не "new Parent()"? Потому что, во-первых, нам не нужно вызывать конструктор, во-вторых, Class.prototype.constructor должен быть равен самому классу, а при создании через new он будет равен родителю.

Но ты таки присмотрись к ES6.

ES6... Смущает то, что его, как ты говоришь, нужно "компилировать". Тем более туда ведь ещё будут вноситься изменения. Не придётся ли потом код переписывать?

Спасибо за пример реализации. Буду курить дальше.

Erolast 25.10.2014 20:00

Цитата:

ES6... Смущает то, что его, как ты говоришь, нужно "компилировать".
После должной настройки это один хоткей в редакторе.

Цитата:

Тем более туда ведь ещё будут вноситься изменения. Не придётся ли потом код переписывать?
До релиза три месяца осталось. Каких-то глобальных изменений уже не должно быть.

Voronar 25.10.2014 20:08

Цитата:

Сообщение от Erolast (Сообщение 337562)
После должной настройки это один хоткей в редакторе.


До релиза три месяца осталось. Каких-то глобальных изменений уже не должно быть.

Посмотрю на досуге новый стандарт, но ещё всё-таки смущает поддержка разными браузерами, а главное Qt WebKit'ом.

Erolast 25.10.2014 20:12

https://developer.mozilla.org/ru/doc...ort_in_Mozilla
http://wiki.ecmascript.org/doku.php?id=harmony:harmony

Sweet 25.10.2014 20:30

Цитата:

Сообщение от Voronar
А почему вместо Object.Create() не использовать просто new?

Через new - это бородатый быдло паттерн. В конструкторе может быть логика, присвоение каких-либо свойств. Он может вызываться с агрументами и пр. А такая реализация абстрагирована от конструктора. И ваще труЪ!

terminator-101 25.10.2014 20:40

Цитата:

Сообщение от Sweet
абстрагирована от конструктора.

Object.create(Parent.prototype, {
	    constructor: {

Ну-ну

Voronar 25.10.2014 20:41

Ещё такой вопрос. В новом стандарте есть какие-то коренные изменения, затрагивающие, например, механизм и структуру построения объектов. Все старые ухищрения будут работать или они уже не понадобятся?

Sweet 25.10.2014 20:42

Цитата:

Сообщение от terminator-101
Ну-ну

Что? Не восстанавливают ссылку на конструктор только педики.

Erolast 25.10.2014 20:44

Цитата:

Ещё такой вопрос. В новом стандарте есть какие-то коренные изменения, затрагивающие, например, механизм и структуру построения объектов. Все старые ухищрения будут работать или они уже не понадобятся?
Классы в ES6 - это синтаксический сахар над уже существующей в JS системой. Все старые ухищрения работать будут.

terminator-101 25.10.2014 20:47

Цитата:

Сообщение от Sweet
Не восстанавливают ссылку

Ты сказал, что она абстрагирована от конструктора. И да, ты хочешь сказать, что это чисто формальность, и на работу кода не влияет или чо? Что значит по-твоему "абстрагирована от конструктора", поясни.

Erolast 25.10.2014 20:53

Речь о том, что при применении new вызовется конструктор, а этого делать не надо, ибо в нем может быть
Цитата:

логика, присвоение каких-либо свойств
и прочая ненужная хрень. Задание правильного свойства constructor прототипу - это другое.

terminator-101 25.10.2014 21:02

Цитата:

Сообщение от Erolast
ибо в нем может быть

Что значит, может быть. Имеется в виду случай, когда кто-то другой пишет конструктор? Если ты сам его писал, как для тебя может быть загадкой, какая в нем логика, и какие там свойства?

Используя конструктор, ты убиваешь сразу 2-х зайцев: создаешь объект с готовыми свойствами, и его прототип, и связь с этим прототипом. К тому же, это готовая фабрика. Object.create -- 'это заведомо более слабый вариант. Все что он делает -- создает объект с нужным прототипом(я тут не рассматриваю опционального аргумента -- это мелочь). Мы это могли бы делать и по старинке. {__proto__: example}, причем последняя даже лучше, поскольку в одном выражении можно создать и объект и св-ва без выкрутасов.


Часовой пояс GMT +3, время: 03:58.