Pull to refresh

Comments 12

Не очень люблю кофескрипт и не пишу на нем, но с нейсмпейсами, импортами и абстрактными методам — очень остроумно.
Ну в случае абстрактных методов — они должны выкидывать ошибки при отсутствии их реализации в ребёнке, в моём случае — только при вызове, что не совсем отвечает требованиям. Но в качестве простенькой «защиты» от ошибок реализации потомков — вполне сойдёт, наверное.
Прямо питоновский raise NotImplementedError.
«Константы». __define(Getter|Setter)__ — нестандартные свойства — IE11+, явно не для продакшна. К слову, на нем JS уже поддерживает ключевое слово const (ES6). Уж лучше, хотя бы defineProperty (ES5, IE9+). А еще лучше дурью не маяться.
Имена классов. Какой-то совсем упоротый подход. Общепринятый способ получения внутреннего класса — Object::toString.call(it).slice 8, -1, а на пользовательские после сжатия кода и ваше решение работать не будет, тут разве что поможет свойство — подсказка (аналог Symbol.toStringTag).
Странное у вас представление о приватности. new Some()['[private test]'] доступно и снаружи. Лучше в сторону символов (Symbol) и их полифилов посмотрите, не совсем приватные свойства, но куда честнее ваших.
1) В случае __define(Getter|Setter)__ — можно сделать откат в ИЕ до обычных переменных (да, не подумал про него, когда писал), смысл ведь в том, что бы разработчик смог получить значение оной переменной и получить ошибку, если попробует переопределить её.
2) Упоротый или нет, но можно получить через name, а откат для ИЕ выдран из оригинала (там ссылочка). К слову — минификация никак не повлияет, т.к. toString для функции вернёт всегда с отступами и прочим. Но можно заменить на Ваш вариант, ничего страшного.
3) new Some()['[private test]'] не доступно, т.к. содержит невидимые чары, которые можно воспроизвести лишь используя магию и num-клавиатуру, а оно надо? Ведь главное — красиво и наглядно показать разработчику, что к ним обращаться не стоит. По поводу Symbol — есть ссылочка? Гугл и can i use посылают меня куда-то не туда…
минификация никак не повлияет

Функция function SomeClass(){/* ... */} будет сжата до какой-нибудь function vE(){}, что и будет содержаться в toString. name тоже нестандартное свойство и не поддерживается IE. Совсем.

не доступно, т.к. содержит невидимые чары

Эти «невидимые» чары легко подбираются и постоянны для всех «приватных» свойств. «Приватные» свойства участвуют в переборе объекта через for-in и получаются через Object.keys.

По поводу Symbol — есть ссылочка?

Символы — новый тип данных в ES6, пример использования полностью аналогичен вашему. Символы уникальны — единственный способ получить ключ вне IIFE — предназначенный для рефлексии метод Object.getOwnPropertySymbols, символы не участвуют в обходе через for-in и недоступны через Object.keys. Доступны в V8 (с 38 Chrome — без флажка) и FF (с 33). Обещают в IE12. Полный полифил не возможен — нельзя добавить новый тип данных, но базовые возможности (уникальные неперечислимые ключи) легко реализовать генерацией уникальной строки и сеттерами в прототипе Object (эта часть решения сомнительна).
Благодарю за подробности, буду знать, но думаю поправлять статью (в связи с новыми подробностями) уже нет смысла — очень многое придётся переписывать.

В любом случае из всего моего перечисленного — только namespace's претендуют на роль использования в продакшене (ну может ещё дефайны), остальное — скорее размышления на тему, как можно ещё улучшить язык и чего бы ещё туда всунуть без лишних хлопот.
Что только люди ни придумают, чтобы не использовать модули.
Кофе — ООП направленный язык, так что вполне логично предполагать, что классы доступны глобально в своём пространстве имён, без всяких require.

Причём, по моему скромному мнению — пространства красивее, нежели модули. Хотя может просто это сказывается совершенно неуместная любовь к Java, C#, PHP, etc…
Во-первых, JavaScript — язык с прототипным наследованием. Объекты наследуются от объектов. CoffeeScript этот факт никак не меняет. Директива class — не более чем синтаксический сахар, преобразующийся при компиляции в подобие Query.extend().

Во-вторых, глобального пространства имен в JavaScript нет. То, что принято называть глобальными переменными, на самом деле является свойствами корневого объекта (в браузере это объект window). Как пользователь CoffeeScript вы должны это знать, ведь единственный тамошний способ объявить «глобальную переменную» — это window.foo = 'bar'.

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

Использование модулей обе проблемы решает кардинально. Рассмотрим для примера модули CommonJS.

У CommonJS два источника модулей: пакетный менеджер NPM и локальные файлы. В первом случае зависимости подключаются по названию пакета (require 'foo'), во втором — по относительному пути (require './foo'). Ни в том, ни в другом случае, вы не сможете создать два пакета, использующие одинаковое имя.

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

$ = require 'jquery'

$ '.foo'
  .bar()

Поверьте, это гораздо проще, удобнее и красивее, чем пространства имен.

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

PS По поводу приватных переменных и в особенности приватных методов разделяю вашу боль. Но JS это такой язык, кишками наружу. Ничего не поделаешь, остается толко использовать костыли вроде jQuery UI Widget Factory. Кстати, горячо рекоммендую.
В-третьих, существуют две смежные проблемы, проистекающие из вышесказанного: коллизии имен и разрешение зависимостей. Ваш подход облегачет первую пролему, не устраняя ее, и никак не помогает со второй.

ну можно создать такой же синтаксический сахар для подгрузки классов. Вместо:
{Some} = Any.Ololo
писать:
Some = import Any:Ololo:Some
Получается тоже самое, что и модули. Осталось только не пихать всё в window, а хранить внутри — будет копия.

На счёт приватных переменных — есть одна общепринятая практика (это так, к слову) — называть методы\переменные с нижнего подчёркивания. Но да, это не особо удобно, боль.
Sign up to leave a comment.

Articles