Javascript способ дизайна наследования + конфиденциальность

Я прочитал книгу Дугласа Крокфорда "JavaScript: хорошие части" и многие другие ресурсы, и я немного запутался в реализации наследования и конфиденциальности в Javascript.

Я из Java World, я понял, что могу симулировать конфиденциальность с помощью замыкания или наследования с помощью прототипа, но я хочу сделать это с помощью JavaScript.

Я знаю, что могу выполнить некоторое наследование по прототипу / паразиту. Это хорошо для производительности, но нет способа правильно использовать некоторые элементы конфиденциальности (без создания какой-либо функции закрытия каждый раз, когда создается новый объект)

Я знаю, что могу наследовать от объекта и использовать элементы приватности через шаблон функционала / паразита, такой как предложенный Дугласом Крокфордом, но есть очевидная проблема производительности / памяти, так как функции будут создаваться снова каждый раз, когда создается объект.

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

Должен ли я считать, что передовой опыт в Javascript сводится к наследованию прототипов / паразитов с открытым интерфейсом и надеюсь, что разработчики будут использовать библиотеку, как ожидается? Или, может быть, мышление в терминах наследования и инкапсуляции - это "Java" способ мышления, а не Javascript? Как использовать возможности утиного программирования в javascript для достижения этих целей?

2 ответа

Решение

Я лично не согласен с большинством вещей в этой книге и нахожу их очень плохо аргументированными. Если нет, то большинство из них совершенно не имеют значения из-за строгого режима и современных инструментов, таких как jshint. Но я думаю, что это просто проблема с тем, насколько устаревшей является книга, поскольку они не были доступны в то время.

Объектная модель языка была расширена в 2009 году множеством новых функций и методов, которые сделали разницу между переменными и свойствами еще больше. Если 10 лет назад можно было притворяться, что переменные - это свойства, то это, конечно, не сейчас.

Для сообщения о том, что что-то не является частью опубликованного API, используется префикс подчеркивания, например:

this._age = 5;
this._method();

Это может иметь особое значение для современных IDE, но не имеет никакого специального значения для рефлексивных методов в языке, таких как for..in а также getOwnPropertyNames,

Существует множество руководств и руководств о том, как использовать шаблон прототипа конструктора natural* для выражения концепции класса.

* Определение естественного, которое я использую, означает, что движки JavaScript распознают и оптимизируют.

Как безопасно наследовать личные данные в JavaScript

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

Почему подчеркивание плохая идея

Подчеркивание не гарантирует конфиденциальность данных, и они создают пару важных проблем:

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

Это проблемы, потому что инкапсуляция является важной особенностью объектно-ориентированного проектирования. Объекты существуют для решения конкретной проблемы. Частные методы могут решить проблемы, которые связаны только с деталями реализации. Детали реализации, скорее всего, изменятся, чем общедоступные интерфейсы, поэтому код, который опирается на детали реализации, может сломаться при изменении деталей реализации.

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

Используйте функциональное наследование для истинной конфиденциальности данных

Функциональное наследование может использоваться для наследования личных данных.

Функциональное наследование - это процесс наследования функций путем применения функции дополнения объекта к экземпляру объекта. Функция предоставляет область закрытия, которая позволяет скрывать личные данные внутри функции закрытия.

Дуглас Крокфорд ввел термин "JavaScript: хорошие детали". В примере Крокфорда дочерняя фабрика знает, как создать экземпляр объекта из существующей базовой фабрики, что приводит к созданию иерархии наследования. Однако это плохая идея. Мы всегда должны отдавать предпочтение композиции объектов, а не наследованию классов.

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

Функциональный миксин усиливает предоставленный экземпляр объекта. Область закрытия функции может содержать закрытые методы и данные. Затем вы можете выставить привилегированные методы внутри этой функции. Это работает так:

const withFlying = instance => {
  let canFly = true; // private data
  let isFlying = false;

  // Privileged method
  instance.fly = () => {
    isFlying = canFly ? true : isFlying;
    return instance;
  };

  // Privileged method
  instance.land = () => {
    isFlying = false;
    return instance;
  }

  // Privileged method
  instance.getFlightStatus = () => isFlying ? 'Flying' : 'Not flying';

  return instance;
};

// Create a new object and mix in flight capability:
const bird = withFlying({});
console.log(bird.fly().getFlightStatus()); // true

bird.land();
console.log(bird.getFlightStatus()); // false

Функциональные миксины могут быть составлены вместе, используя стандартную композицию функций с любым другим базовым объектом и любым другим набором функций. Во-первых, вам понадобится функция compose. Ты можешь использовать compose() от Lodash, Ramda или любой библиотеки функционального программирования, которая предоставляет стандартную функцию compose - или просто напишите свою собственную:

// Function composition: Function applied to the result of another function application, e.g., f(g(x))
// compose(...fns: [...Function]) => Function
const compose = (...fns) => x => fns.reduceRight((acc, fn) => fn(acc), x);

Теперь вы можете составить любое количество миксинов вместе, используя стандартную композицию функций:

// This function returns a function which can be used
// as a functional mixin.
// `text` here is private data that determines the sound
// `quack()` will log to the console.
const withQuacking = text => instance => {
  // Privileged method
  instance.quack = () => console.log(text);
  return instance;
};

// Compose mixins:
// ('Quack!' is private data)
const createDuck = compose(withFlying, withQuacking('Quack!'));

const malard = createDuck({});

console.log(malard.fly().getFlightStatus()); // Flying
malard.quack(); // "Quack!"

Для более гибких способов составления фабричных функций с использованием различных методов наследования см. Спецификацию штампа.

Рекомендации:

Другие вопросы по тегам