Javascript-форум (https://javascript.ru/forum/)
-   Общие вопросы Javascript (https://javascript.ru/forum/misc/)
-   -   Определение прототипа через объект (https://javascript.ru/forum/misc/60478-opredelenie-prototipa-cherez-obekt.html)

Keramet 02.01.2016 19:48

Определение прототипа через объект
 
Обычно прототипы определяют так:
1.
function Person() {}
Person.prototype.name = "аноним";
Person.prototype.age = 18;

А если определить прототип так:
2.
function Person() {}
Person.prototype = {
  name : "аноним",
  age : 18
};

Эти фрагменты эквивалентны или нет?

callbackhell 02.01.2016 20:19

Да, но возможно это скажется на производительности.

vasa_c 02.01.2016 20:23

в изначальном prototype могут быть всякие полезности. например свойство constructor по которому можно пройтись по цепочке прототипов.
во втором случае его не будет.

callbackhell 02.01.2016 20:27

Цитата:

Сообщение от vasa_c
во втором случае его не будет.

можно явно указать его. Но вообще, конструкторами пользуются только идиоты(коих большинство, к сожалению). А по цепочкам прототипов ты и без этого говна можешь пройтись, есть __proto__

Keramet 02.01.2016 20:30

callbackhell,
Я вот тоже так думал, но:
1.
function Person() {}
var p1 = new Person();
Person.prototype.name = "Nicholas";
Person.prototype.age = 29;

var p2 = new Person();

alert ( Person.prototype.isPrototypeOf(p1) ) ;
alert ( Person.prototype.isPrototypeOf(p2) ) ;
	
alert ( p1 instanceof Person ) ;
alert ( p2 instanceof Person ) ;
	
alert ( p1.constructor ) ;
alert ( p2.constructor ) ;


2.
function Person() {}
var p1 = new Person();
Person.prototype = {
	name : "Nicholas",
	age : 29
};

var p2 = new Person();

alert ( Person.prototype.isPrototypeOf(p1) ) ;
alert ( Person.prototype.isPrototypeOf(p2) ) ;
	
alert ( p1 instanceof Person ) ;
alert ( p2 instanceof Person ) ;
	
alert ( p1.constructor ) ;
alert ( p2.constructor ) ;


дают разные результаты. В чём подвох - не пойму :(

callbackhell 02.01.2016 20:38

Цитата:

Сообщение от Keramet
В чём подвох - не пойму

Да, это все не будет работать, но оно не нужно в реальном коде, забейте. Эти ссылки скрыты и они создаются нейтивом:)

Keramet 02.01.2016 20:40

Цитата:

Сообщение от callbackhell (Сообщение 402267)
... Но вообще, конструкторами пользуются только идиоты(коих большинство, к сожалению)...

А можно уточнить, чем так плохи конструкторы и чем пользуется "меньшинство" :) ?

Keramet 02.01.2016 20:46

Цитата:

Сообщение от callbackhell (Сообщение 402271)
Да, это все не будет работать, но оно не нужно в реальном коде, забейте. Эти ссылки скрыты и они создаются нейтивом:)

Возможно мои размышления наивны (я только начал изучение ДжС), но при нарушении цепочки прототипов, я не смогу полноценно реализовать наследование. поправьте, если я неправ

callbackhell 02.01.2016 20:47

Вы к примеру, можете сделать вот так
MySuperClass = {type: "MySuperClass"}
MyClass = Object.create(MySuperClass); MyClass.type = "MyClass"
o1 = Object.create(MySuperClass)
o2 = Object.create(MyClass)

alert([o1.type, o2.type])

Это замена instanseOf. Когда вы освоитесь в прототипном программировании, вы удивитесь, насколько гибкие решения оно дает в плане ООП. А используя нативные конструкторы, а тем более es6-классы, вы опускаете язык до уровня какой-нибудь java. Конструкторы имеет смысл пользовать только для производительности.

callbackhell 02.01.2016 20:49

Цитата:

Сообщение от Keramet
но при нарушении цепочки прототипов

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

callbackhell 02.01.2016 21:00

Keramet,
Особенно конструкторы будут Вам мешать при создании сабклассов. Тот пример котрый я привел, например, пишется с конструкторами через жопу и с кучей костылей. как-то так:)

Keramet 02.01.2016 21:02

Цитата:

Сообщение от callbackhell (Сообщение 402276)
Нет никакого нарушения цепочек. Вы сами же эти цепочки и реализуете, в этом и заключается Ваша реализация наследования.

ну насколько я понял, при обращении к свойству объекта, если это свойство не определено в этом экземпляре, оно (св-во) ищется по цепочке прототипов (вплоть до Object.prototype). Если и там нет - то выдается undefined. Я поэтому и считаю - что при нарушении цепочки можно получить не то, что ожидалось

callbackhell 02.01.2016 21:23

Keramet,
Еще раз повторяю, разрушить ничего нельзя, потому что ничего нет. Вы сами строите цепочки наследования. Это Ваша забота выстроить их так как нужно

Keramet 02.01.2016 21:31

Стоп! "Чуть по-медленнее, я запиСУЮ.."
Конструкторы и прототипы придумали для того, чтобы реализовать наследование в ДжС, т.к. он (ДжС) не поддерживает классы. правильно?

callbackhell 02.01.2016 21:36

Цитата:

Сообщение от Keramet
правильно?

Нет не правильно. Прототипное ООП не нуждается ни в каком синтаксисе для классов, для того чтобы ПОЛНОСТЬЮ поддерживать ООП-парадигму, в том числе и наследование. Прототип JS -- язык Self, язык более мощный чем JS, там ЕМНИП, поддерживается в том числе множественное наследование, и там нет синтаксиса для классов. Айк ввел new и некоторое другое дерьмо для того чтобы JS был похож на жабу, это был маркетинговый ход. И он сожалеет об этом, он писал это в своих воспоминаниях.

Keramet 02.01.2016 21:52

callbackhell,
меня учили, что ООП - это программирование, основными характеристиками которого является инкапсуляция, наследование и полиморфизм (я закончил ВУЗ лет 15 назад, может что-то изменилось:)) в классических ООП языках (джава, С++) для этих целей применяюстя классы. в ДжС классов нет, тут есть прототипы. правильно?

callbackhell 02.01.2016 21:55

Цитата:

Сообщение от Keramet
в ДжС классов нет, тут есть прототипы. правильно?

Сейчас уже есть, к сожалению. Но классы -- это лишняя сущность. К тому же они реализованы отвратительно, их лучше не использовать, если Вам нужна гибкость.
Цитата:

Сообщение от Keramet
в классических ООП языках

С этим тоже надо поосторожней. Вас в вузе не учили, кто ввел термин ООП? И как он относится к перечисленным Вами языкам. Я бы назвал это квазиооп.

Keramet 02.01.2016 21:58

Цитата:

Сообщение от callbackhell (Сообщение 402305)
Вас в вузе не учили, кто ввел термин ООП?

Берн Страуструп?

Keramet 02.01.2016 22:02

Цитата:

Сообщение от callbackhell (Сообщение 402305)
Сейчас уже есть, к сожалению.

я ни в одной книги не сталкивался. они (классы) уже в ES5 есть или их только планируют вводить?

callbackhell 02.01.2016 22:03

Цитата:

Сообщение от Keramet
Берн Страуструп?

Вы шутите?
Цитата:

I made up the term 'object-oriented', and I can tell you I didn't have C++ in mind

-- Alan Kay,
Вы по какой специальности учились? Филология?

callbackhell 02.01.2016 22:04

Цитата:

Сообщение от Keramet
уже в ES5 есть или их только планируют вводить?

В ES6. Уже поддерживаются новыми браузерами

Яростный Меч 03.01.2016 19:37

Цитата:

Сообщение от Keramet (Сообщение 402268)
callbackhell,
Я вот тоже так думал, но:
1.
function Person() {}
var p1 = new Person();
Person.prototype.name = "Nicholas";
Person.prototype.age = 29;

var p2 = new Person();


2.
function Person() {}
var p1 = new Person();
Person.prototype = {
	name : "Nicholas",
	age : 29
};

var p2 = new Person();


дают разные результаты. В чём подвох - не пойму :(

в первом случае p1.__proto__ и p2.__proto__ ссылаются на один и тот же объект - Person.prototype. Он не менялся, в него просто добавили два поля.
Во втором - p1.__proto__ ссылается на предыдущий Person.prototype, который был заменен новым объектом уже после создания p1. И потому p1 более не считается экземпляром Person, с точки зрения прототипного ООП.

Второй случай вполне допустим, только заменять Person.prototype надо сразу же при создании функции Person, до создания экземпляров. И не забыть туда свойство constructor поместить, о чем ранее говорилось. Тогда всё будет нормалёк.

Ну а ежели какое наследование замутить изволите, то там особо без вариантов:
Person.prototype = Object.create(ParentClass.prototype);
и далее добавление методов по первой схеме.

Яростный Меч 03.01.2016 19:44

Цитата:

Сообщение от callbackhell (Сообщение 402305)
Сейчас уже есть, к сожалению. Но классы -- это лишняя сущность. К тому же они реализованы отвратительно, их лучше не использовать, если Вам нужна гибкость.

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

Вот что там действительно новое - "методы, привязанные к объектам". Штука в целом полезная и нужная.
https://learn.javascript.ru/es-object#методы-объекта

googlecallback 03.01.2016 19:54

Цитата:

Сообщение от Яростный Меч
Да не так уж и плохо реализованы.

Угу, проперти в классе использовать нельзя, классы -- не ферст-класс объекты, следовательно нет метаобъектного программирования, для ссылок на суперкласс надо пользовать какие то нелепые костыли (без них this не биндится), можно продолжать, но уже достаточно чтобы забыть навсегда. Для такого динамического яп как js такой запил -- это форменное издевательство.

Яростный Меч 03.01.2016 20:14

Цитата:

Сообщение от googlecallback (Сообщение 402435)
проперти в классе использовать нельзя,

можно
https://learn.javascript.ru/es-class...войства

Цитата:

Сообщение от googlecallback (Сообщение 402435)
классы -- не ферст-класс объекты, следовательно нет метаобъектного программирования,

function createClass() {
    'use strict';
    class User {
      constructor(name) {
        this.name = name;
      }
      sayHi() {
        alert(this.name);
      }
    }
    return User;
}

function createObject(Class, param) {
    return new Class(param);
}

var User = createClass();
var user = createObject(User, "UserName123");
user.sayHi();
есть так же Class Expression, в общем, всё как положено.


Цитата:

Сообщение от googlecallback (Сообщение 402435)
для ссылок на суперкласс надо пользовать какие то нелепые костыли

вот как раз вызывать методы родительского класса стало проще простого, а раньше было геморно

googlecallback 03.01.2016 20:14

Цитата:

Сообщение от Яростный Меч
"методы, привязанные к объектам". Штука в целом полезная и нужная.

Она "нужная" для JS только потому, что в нем используются говнопрактики проектирования, когда объекты заметаются под ковер. Эдакий недофапе - стайл на одних коллбеках
В нормальных ЯП с этим проблем нет. Там Вы писали бы что то такое
theTimeout = Timeout.create
theTimeout.a = 1

object = {
   a: 10,
   fu1: staticFunction(){alert(a)},
   fu2: dynamicFunction(){alert(a)}
}

theTimeout.addOnTimeout(object.fu1)
theTimeout.addOnTimeout(object.fu2)

//>>>1, 10

Яростный Меч 03.01.2016 20:18

Цитата:

Сообщение от googlecallback (Сообщение 402439)
Она "нужная" для JS только потому, что в нем используются говнопрактики проектирования, когда объекты заметаются под ковер. Эдакий недофапе - стайл на одних коллбеках
В нормальных ЯП с этим проблем нет. Там Вы писали бы что то такое
theTimeout = Timeout.create
theTimeout.a = 1

object = {
   a: 10,
   fu1: staticFunction(){alert(a)},
   fu2: dynamicFunction(){alert(a)}
}

theTimeout.addOnTimeout(object.fu1)
theTimeout.addOnTimeout(object.fu2)

//>>>1, 10

Ну вот и в JS появилось то же самое.

googlecallback 03.01.2016 20:28

Цитата:

Сообщение от Яростный Меч
вот как раз вызывать методы родительского класса стало проще простого, а раньше было геморно

В чем гемор?

googlecallback 03.01.2016 20:42

Яростный Меч,

Да, я наверное, плохо ознакомился, частично я не прав, тем не менее.

Классы нельзя считать первоклассными сущностями уже потому, что их протокол отличается от объектного. В них нельзя иметь проперти. Насколько я подозревю, ими нельзя манипулировать с помощью Object.defineProperty, так? Они, вероятно, не поддерживают проксирование. Сабклассинг неуклюж, всегда надо забивать голову оверррайдами. Требуют строгого режима. Если там копнуть глубже, всплывет еще куча дерьма.

Все равно при "классовом" подходе теряется гибкость. Я могу на коленке реализовать такие классы за пять минут, но могу и другие, с другой семантикой, ничего это не дает, по сути, просто еще один костыль.

googlecallback 03.01.2016 20:48

Яростный Меч,
Единственное ощутимое преимущество -- эт унификация кода в ынтырпрайзе. Но меня это не касается лично:)

Яростный Меч 03.01.2016 21:55

Цитата:

Сообщение от googlecallback (Сообщение 402442)
В чем гемор?

В самом простом случае вызов родительского метода выглядит так:
...
method1: function(...) {
  ParentClass.prototype.method1.call(this, ...);
},
...
вроде ничего страшного, но выглядит как-то не очень, и родительский класс напрямую упоминается, если менять, то по всему коду.

есть ещё всякие реализации классов, там этих проблем нет, но реализовано через костыли.

В новых классах всё просто:

...
method1: function(...) {
  super.method1(...);
},
...
и this передается как надо, и родительский класс не упоминается

Яростный Меч 03.01.2016 21:59

Цитата:

Сообщение от googlecallback (Сообщение 402446)
Классы нельзя считать первоклассными сущностями уже потому, что их протокол отличается от объектного.

не очень понял насчет "протокола", но классы можно передавать в параметры функций, возвращать через return, создавать "на лету". Вроде как этого достаточно для "объектов первого класса"

googlecallback 03.01.2016 21:59

Цитата:

Сообщение от Яростный Меч
В самом простом случае вызов родительского метода выглядит так:

Это какое то феерическое говно. Родительский метод наследуется, поэтому вызов foo.bar(), а внутри методов function(){this.bar()}. Не ожидал от вас такого даже, на первый вгляд мне показалось, что Вы разбираетесь.

googlecallback 03.01.2016 22:05

Цитата:

Сообщение от Яростный Меч
Вроде как этого достаточно для "объектов первого класса"

Первоклассные объекты языка -- да (да и то еще вопрос, ибо требуют строгого режима), но первоклассные объекты в смысле ООП -- нет. Напимер, строки -- тоже первоклассные объекты, но не полноценные.

vasa_c 03.01.2016 22:24

Я не часто на этом форуме бываю, но как я понял, здесь максимаксимус с самим собой дискутирует?

googlecallback 03.01.2016 22:26

vasa_c,
Ты даже до его уровня не дорос, не обольщайся

vasa_c 03.01.2016 22:28

googlecallback, да я разве где-то пытался утверждать обратное? упаси осподи.
Я просто поинтересовался, чтобы случайно не вляпаться.

googlecallback 03.01.2016 22:36

Цитата:

Сообщение от Яростный Меч
не очень понял насчет "протокола"

Грубо говоря, единый протокол означает поддержку единого интерфейса. Если, к примеру, Вы не можете сделать myClass.foo = bar, значит классы не поддерживают объектный протокол в полной мере


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