Эта статья начиналась как комментарий к другой статье на habrahabr. После написания первого листа, я понял, комментарий слишком обширный получился :). Я решил написать, потому что хочу заострить внимание на моментах, которые, на мой взгляд, были упущены. Ограничение этой статьи — моя цель изложить всё максимально доступно, не ищите здесь математической точности в определении терминов, и всё же я прилагаю ссылки где математики найдут высококлассные понятные только им определения :)
Наверно каждую статью по JS принято начинать со слов о его недооцененности :) Это правда :) Когда я пару лет назад говорил о том что JS мой любимый язык на меня смотрели, как на школьника-переростка, который только что написал свою первую страницу на HTML, а те кто меня знал, как на гроссмейстера, который сказал что он только и знает как фигуры ходят :). Таких людей не стало намного меньше, увы :(
Итак, момент первый — ничего не сказано о том чем Javascript отличается принципиально от Java или С++. Отличие в подходе (парадигме) программирования взятой за основу при создании языка. Я не оцениваю «что лучше?», ни в коме случае, кому что удобнее :) или нравиться :)
Большинство людей, которые смотрят на JS свысока говорят о нем, как не о ООП языке :). Начнем с того, что это разные вещи и их вообще нельзя сравнивать. Конечно можно программировать на JS пользуясь навыками полученными при программировании на C++ или Java, но это так не эффективно. JS работает иначе, в нём нет классов, в нём есть объекты (не падайте в обморок, дочитайте статью). Это не означает, что на JS невозможно сделать абстракции, инкапсуляции, наследование или полиморфизма. Главные отличия в реализации инкапсуляции, наследования, и работе конструктора. В JS, как и почти во всех языках прототипного типа, нужно использовать термин инкапсуляции, есть замыкание.
Замечу, что на хабре уже была статья о замыканиях. Попробую объяснить «на пальцах» и добавлю пример.
Замыканиями в JS называют область видимости внутри которой переменная обретает смысл :). Это может быть определение объекта или функции. Переменная может быть как примитивной, так и объектом или функцией. Уф… теперь, любимое, пример:
Давайте по порядку :)
т.к после прохода циклом i = count, то без этих скобок, мы получим совсем другой ответ — постоянный 10'000, а с ними 27.
Кстати, этот приём называется разрывом замыкания.
Именно поэтому в jQuery рекомендуют писать плагины к этому фреймверку внутри конструкции(… ваш плагин...)();, это позволяет:
Вот я недавно написал, что в JS нет классов, а есть объекты. Я имел в виду следующее:
В класс-ориентированных языках новый экземпляр создается через вызов конструктора класса (возможно, с набором параметров). Получившийся экземпляр имеет структуру и поведение, жёстко заданные его классом. Вот строчки из Википедии:
«open 4» мы не получим, т.к. метод open у нас определен в самом объекте, что не касается save.
Внимательный читатель меня спросит — а где же в этой дьявольской смеси конструктор? Да, здесь его не было. Конструктором является сам объект, запускается при создании клона, с помощью оператора new или инициализации самого объекта. Демонстрация:
В JS нет наследования и тем более множественного. У каждого объекта есть прототип, объект который можно сделать общим для нескольких объектов или их экземпляров, а потом менять :)
Ребятам молящимся на парадигму ООП, проснитесь, есть много других парадигм программирования. Нет лучшей, есть наиболее подходящие для определенных задач. JS один из языков на долго занявших свою нишу, в том числе потому что под ним очень мощный фундамет прототипной прарадигмы программирования.
Остальные, надеюсь узнали что-нибудь полезное :)
С уважением, Артур Дудник
самая ценная человеческая черта — стремление к самосовершенствованию ©
Наверно каждую статью по JS принято начинать со слов о его недооцененности :) Это правда :) Когда я пару лет назад говорил о том что JS мой любимый язык на меня смотрели, как на школьника-переростка, который только что написал свою первую страницу на HTML, а те кто меня знал, как на гроссмейстера, который сказал что он только и знает как фигуры ходят :). Таких людей не стало намного меньше, увы :(
Итак, момент первый — ничего не сказано о том чем Javascript отличается принципиально от Java или С++. Отличие в подходе (парадигме) программирования взятой за основу при создании языка. Я не оцениваю «что лучше?», ни в коме случае, кому что удобнее :) или нравиться :)
Отличие традиционной класс-объектной от прототипной парадигмы
Большинство людей, которые смотрят на JS свысока говорят о нем, как не о ООП языке :). Начнем с того, что это разные вещи и их вообще нельзя сравнивать. Конечно можно программировать на JS пользуясь навыками полученными при программировании на C++ или Java, но это так не эффективно. JS работает иначе, в нём нет классов, в нём есть объекты (не падайте в обморок, дочитайте статью). Это не означает, что на JS невозможно сделать абстракции, инкапсуляции, наследование или полиморфизма. Главные отличия в реализации инкапсуляции, наследования, и работе конструктора. В JS, как и почти во всех языках прототипного типа, нужно использовать термин инкапсуляции, есть замыкание.
Замыкание
Замечу, что на хабре уже была статья о замыканиях. Попробую объяснить «на пальцах» и добавлю пример.
Замыканиями в JS называют область видимости внутри которой переменная обретает смысл :). Это может быть определение объекта или функции. Переменная может быть как примитивной, так и объектом или функцией. Уф… теперь, любимое, пример:
- function bicubic(count)
- {
- var values = [];
-
- for (var i = 0; i < count; i++)
- {
- values[i] = (
- function(n)
- {
- return function()
- {
- return Math.pow(n, 3);
- }
- }
- )(i);
- }
-
- return values;
- }
-
- var vals = bicubic(10);
-
- alert( vals[3]() );
* This source code was highlighted with Source Code Highlighter.
Если бы мне показали эти строки и попросили бы сказать «что это за хрень такая» я бы не одну минуту потратил, чтоб разобраться :) Именно это и придает столько силы сторонником JS в утверждении, что языки основанные на классах приводят при написании кода к излишней сфокусированности программистов на иерархичности и связях классов друг с другом, что по моему правда.Давайте по порядку :)
- Создается функция bicubic которая выдает массив;
- Фишка в том, что является членами массива — это функции без параметра: Math.pow(n, 3). В данном случае n, благодаря чуду замыкания становиться значением i в момент прохода цикла, а не после него!
- Волшебство в скобках (...)(i) — это вызов функции с параметром i, а в скобках определение этой функции.
т.к после прохода циклом i = count, то без этих скобок, мы получим совсем другой ответ — постоянный 10'000, а с ними 27.
Кстати, этот приём называется разрывом замыкания.
Именно поэтому в jQuery рекомендуют писать плагины к этому фреймверку внутри конструкции
- Писать безопасный код
- Не перегружать браузер глобальными переменными
Экземпляр, конструктор, объект и прототип
Вот я недавно написал, что в JS нет классов, а есть объекты. Я имел в виду следующее:
В класс-ориентированных языках новый экземпляр создается через вызов конструктора класса (возможно, с набором параметров). Получившийся экземпляр имеет структуру и поведение, жёстко заданные его классом. Вот строчки из Википедии:
В прототип-ориентированных системах (например JS) предоставляется два метода создания нового объекта: клонирование существующего объекта, либо создание объекта «с нуля». Для создания объекта с нуля программисту предоставляются синтаксические средства добавления свойств и методов в объект. В дальнейшем, с получившегося объекта может быть получена полная копия, клон. В процессе клонирования копия наследует все характеристики своего прототипа, но с этого момента она становится самостоятельной и может быть изменена. В некоторых реализациях копии хранят ссылки на объекты-прототипы, делегируя им часть своей функциональности; при этом изменение прототипа может затронуть все его копии. В других реализациях новые объекты полностью независимы от своих прототипов.Демонстрация:
- function win() {
- this.open = function()
- {
- return "open 1";
- }
- }
-
- win.open = function() {
- return "open 2";
- }
-
- alert( win.open() ); // 1. open 2
-
- win.prototype = {
- save: function()
- {
- return "open 3";
- }
- }
-
- alert( win.save() ); // 2. error - нет save
-
- win.prototype.open = function()
- {
- return "open 4";
- }
-
- alert( win.open() ); // 3. open 2
-
- var vista = new win();
-
- alert( vista.open() ); // 4. open 1
- alert( vista.save() ); // 5. open 3
-
- vista.open = (
- function()
- {
- return "open 5";
- }
- )();
-
- alert( vista.open ); // 6. open 5
-
- alert( win.open() ); // 7. open 2
* This source code was highlighted with Source Code Highlighter.
«open 4» мы не получим, т.к. метод open у нас определен в самом объекте, что не касается save.
Внимательный читатель меня спросит — а где же в этой дьявольской смеси конструктор? Да, здесь его не было. Конструктором является сам объект, запускается при создании клона, с помощью оператора new или инициализации самого объекта. Демонстрация:
- function win()
- {
- var str = "open 1";
-
- this.open = function()
- {
- return str;
- }
- }
-
- alert( (new win()).open() ); // open 1
* This source code was highlighted with Source Code Highlighter.
Создание объекта «с нуля» в JS, «это вещь»! Приведу пример, который помогает экономить мускульные усилия пальцев:
- function plugin(options)
- {
- options = options || {};
-
- options.list = options.list || [];
-
- // далее можно смело работать
- // options, проверять его свойства, например,
- // а с list как с массивом
- }
* This source code was highlighted with Source Code Highlighter.
Прототип, «наследование» в javascript
очень сложно найти в тёмной комнате чёрную кошку, особенно если там её нет :)
© народная мудрость
В JS нет наследования и тем более множественного. У каждого объекта есть прототип, объект который можно сделать общим для нескольких объектов или их экземпляров, а потом менять :)
Итог
Ребятам молящимся на парадигму ООП, проснитесь, есть много других парадигм программирования. Нет лучшей, есть наиболее подходящие для определенных задач. JS один из языков на долго занявших свою нишу, в том числе потому что под ним очень мощный фундамет прототипной прарадигмы программирования.
Остальные, надеюсь узнали что-нибудь полезное :)
С уважением, Артур Дудник
самая ценная человеческая черта — стремление к самосовершенствованию ©