Pull to refresh

Comments 39

Нда, слегка косяков немного.
User.prototype.sayHey = function() {
  console.log( “Hey, I’m an “ + role);
}

Тут потерялся this. Но это самая безобидная ошибка.

Editor.prototype = Object.create( User.prototype );

После данной строки необходимо восстановить конструктор в прототипе класса Editor, ибо конструктор прилетит от User.

Конструктор можно не восстанавливать если нет необходимости обращаться к этому свойству в дальнейшем.

Чтобы потом другие разработчики крыли матом автора сего кода? Вы можете дать гарантии, что не понадобится в будущем? А потом возможна очень даже весёлая отладка. А уж в статье, которая рассказывает о наследовании и в которой допущена данная ошибка/упущение, это как-то не очень правильно.
Скорее ошибка была допущена когда свойство constructor придумывали.

Насчёт классов в ECMAScript 6 — разве они не введены отчасти для того, чтобы "законно" иметь настоящие классы, без оверхеда от эмуляции через прототипы? Тут недавно проходила статья про оптимизации в V8, так там описывалось, как prototype-based объекты фактически преобразуются в class-based для ускорения, а тут можно сразу быстро сделать.

нет, это просто сахар для тех же прототипов.

Абсолютно уверены? Перечитайте https://habrahabr.ru/post/154537/ и скажите, не сделает ли разумный разработчик javascript-движка классы классами, скатываясь в прототипы только при невозможности остаться в рамках класса?

Конечно же движок будет делать классы классами. Однако ключевое слово class здесь никак не помогает. Потому что с JS-классы можно все так же динамически изменять:


class Point {};
Point.prototype.newMethod = function() {};

const p = new Point();
point.newMethod(); //будет вызвано

В Objective C так тоже можно, хотя язык не на прототипах.
Наверное, в качестве примера вам следовало задать функцию не прототипу, а экземпляру объекта, или переопределить метод где-то в середине цепочки наследования — при этом как раз всплывает разница между наследованием от прототипа и от класса.
Но я понял вашу мысль: что бы там ни было внутри — prototype-based поведение javascript будет эмулироваться до упора.


Моя мысль была — что если написали "class" — можно считать, что это настоящий класс (и получать выигрыш по быстродействию), пока программист не докажет обратное (а во всех руководствах будет написано "не делать так никогда, performance penalty"). Довольно очевидная оптимизация.

Нет, упоминание слова class в исходном коде никак не помогает оптимизатору. До настоящего времени V8 (и другие движки, наверное тоже), научились довольно уверенно детектировать классы которые с prototype


function Point() {}
Point.prototype.method = function() {}

Они уже сейчас довольно неплохо оптимизируются и быстро работают. Упоминание слова class тут ничем не поможет, ибо поведение получившихся объектов все такое же

В class-based объектах совсем не те классы используются.

prototype-based объекты фактически преобразуются в class-based
Не наоборот ли? Везде и всюду написано, что классы — сахар для прототипов.

Статья, где описано преобразование — https://habrahabr.ru/post/154537/
Т.е. на итог получим "классы — сахар для прототипов, которые потом будут преобразованы в классы".
Вот я и думаю — разве создатели js-движка преобразования туда-обратно не захотят убрать? И не думали ли они об этом, ещё когда предложение только вносилось?

Еще раз: классы в JS — это совсем не те скрытые классы, которые используются под капотом V8.

Ok, не те же (в принципе, понятно: скрытые классы делаются и без слова class; можно реализовать классы без скрытых классов, чисто как синтаксический сахар).
Вопрос: при "правильном" использовании класса (все поля инициализируются в конструкторе) объекты одного класса попадут в один скрытый класс?
Если да, то вопрос 2: использует ли это движок для оптимизации?
Ну и чуть сторонний вопрос 3: какой-нибудь linter может отслеживать, чтобы не попасть на деоптимизацию, или это надо переходить на TypeScript?

Вопрос: при "правильном" использовании класса (все поля инициализируются в конструкторе) объекты одного класса попадут в один скрытый класс?

Да. Точно так же как в один скрытый класс попадут все объекты, созданные через одну функцию-конструктор, т.е. ключевое слово class тут ничего не добавляет и не убавляет.


Если да, то вопрос 2: использует ли это движок для оптимизации?

Разумеется, использует. Именно благодаря этому свойству скрытые классы вообще имеют смысл.


Ну и чуть сторонний вопрос 3: какой-нибудь linter может отслеживать, чтобы не попасть на деоптимизацию, или это надо переходить на TypeScript?

Ни то ни другое не гарантирует непопадание на деоптимизацию.

Айтишный русский язык может и состоит чуть больше чем наполовину из англицизмов, но от «дефиниции», честно, сводит скулы. (Вот как теперь стереть это словообразование из головы..)
без риска возникновения коллизий с существующими дефинициями.
или «определениями», или «обьявлениями» или в худшем случае «декларациями». А лучше, вообще опустить это дополнение. Просто, "… без риска возникновения коллизий". Точка.
Русский читатель достаточно сообразителен, и подкован, чтобы понять о чем идет речь.

Мне одному кажется, что подобные статьи в 2017 году на Хабре — это как немного запоздало?

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

Ну так в том и дело, мануал даже 10 летней давности в сравнении с этой статьей актуальности не теряет. Прототипы всегда работали одинаково. Единственное серьезное отличие, которое уже тоже всему разобрано это то, что можно лет как 5 делать


Editor.prototype = Object.create( User.prototype );

вместо


Editor.prototype = new User

Опять же, если говорить про актуальность статьи, приводится выражение


var MyApp = MyApp || {};

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

согласен, если речь про «ванильный» js, то лучше обходиться стандартным синтаксисом языка, либо давать комментарии.
Или чему будет равно
MyApp && {}
(если MyApp это объект, а не undefined/null)

На самом деле, Editor.prototype = new User всегда было плохой идеей. Общепринятый подход после длительных танцев на граблях был такой:


function temp() {}
temp.prorotype = User.prototype;
Editor.prototype = new temp();

Справедливо, иначе конструктор User будет запускаться, и это никому не нужно. Но для совсем корректного наследования нужно еще после всего сделать так:


Editor.prototype.constructor = Editor

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

Что в этой статье, позвольте поинтересоваться, актуального?

На Хабре последнее время засилье таких статей. Компании (в данном случае Райфу, но постоянно вижу подобное и от других компаний), чтобы попиариться, нужно написать статью.

Но ведь новый и интересный контент — это сложно. Проще ещё раз написать то, о чём за 15 лет уже написано вдоль, поперёк и по диагонали.
А если посмотреть ещё и на количество ошибок, страшно предположить, кто писал.

Допустим, с "дефинициями" вместо "определений" и "прототипичным наследованием" вместо "прототипного" еще можно смириться.
Но елки-палки, неймспейсы? Наследование без классов? В 2к17?! Особенно мне нравится пассаж "С появлением ES2015 ситуация начала медленно меняться". Медленно. Медленно?! Да 16-17 годы прошли под знаком статей про "Javascript fatuque" — про усталость, вызванную неимоверно возросшей скоростью развития JS, а вы пишите "медленно"?
Как же у меня бомбит от этой статьи, как же у меня бомбит.
Я понимаю, что это перевод, и претензии немного не по адресу, но надо ж как-то повнимательней относиться к материалу, который публикуете.

Спасибо, благодаря Вашему посту до меня наконец-то дошло что же всё-таки такое прототипы и как с ними работать. Очень легко и понятно объяснено.
Спасибо!

Статья фактически о наследовании в jS, а не об ООП. Будет продолжение?

Создание функции-конструктора аналогично созданию регулярного выражения...
Создание функции-конструктора аналогично созданию обычной функции.
Creating a constructor function is similar to creating a regular function.
JavaScript — мощный объектно-ориентированный (ООП) язык.

чето ржу…
ЕС2015, он же ЕС6, как кому удобнее:
Инкапсуляции нету, вообще никаких модификаторов видимости нет, абстракций/интерфейсов нет, а на ЕС5 еще и наследование с бубном.
Не понимаю, за что заминусовали. Человек правильно говорит. Если в JS есть объекты, это еще не значит, что он объектноориентирован.
Инкапслюция будет только со статическими полями:
var Some = (function() {
  var private; // приватная статическая переменная
  function Some(name) {
    // публичные свойства
    this.publicVar = name;
  }
  Some.prototype = {
    // публичные методы
  };
  return Some;
})();
Модификаторы видимости не являются обязательным признаком объектно-ориентированности. Наследование и полиморфизм — намного более важные «киты» ООП, а они в Javascript присутствуют.

Кстати, инкапсуляцию иногда понимают не как сокрытие данных, а как помещение данных и методов в один контейнер. Согласно этому определению она в JS присутствует.

Впрочем, приватные свойства в JS все же можно получить если по какой-то причине это так важно:

var Some = (function() {
  var private_s = Symbol("private");
  function Some(name, age) {
    this.publicVar = name;
    this[private_s] = age; // Приватное свойство
  }
  Some.prototype = {
    // публичные методы
  };
  return Some;
})();
А в чем сакральный смысл использовать Символ в
var private_s = Symbol(«private»);
private_s уже заклозурена и приватна.

Кстати, инкапсуляцию иногда понимают не как сокрытие данных, а как помещение данных и методов в один контейнер

Ну если не правильно понимают… то поном пишут статейки сколь ужасен ООП.
Инкапсуляция это сокрытие реализации в первую очередь. А ООП в первую очередь это абстракции, когда мне все равно кто и как реализовал функционал. Я как «юзер» объявляю зависимость от определенного интерфейса, а кто и как мне его предоставит — мне без разницы.
А в чем сакральный смысл использовать Символ в
var private_s = Symbol(«private»);
private_s уже заклозурена и приватна.

Ваши предложения?


PS научитесь пользоваться кнопкой "ответить"

Мое предложения сразу на следующей строке. А ответа на вопрос я не получил.
Наследование и полиморфизм

Дааа…
Для того, что бы что бы от чегото унаследоваться цельная функция была) Поиграйся с промежуточным объектом, а потом с прототайпами, конструктор не забудь, иначе поимей проблем с банальным инстес-офом)

Про полиморфизм вообще умолчу. Единственна доступна в ЯС форма «потомка можно использовать как парента». А вы в курсах что потомок может внезапно перестать быть потомком)). Просто паренту прототайп поменяли)))
Sign up to leave a comment.