Pull to refresh

Comments 59

ага :) спасибо, успел :) карма не сильно пострадала :)
UFO just landed and posted this here
Поставил плюс в основном за слова «кому что удобнее» — я сам разделяю такой подход. Тем не менее, в вашей статье много недостатков:

1) JS вполне укладывается в парадигму ООП. В конце концов, впервые слова ООП были сказаны именно о прототипном языке программирования. Просто в JS ООП реализовано в других терминах и другими способами, отличными от используемых в более распространенной «классовой» модели.

2) В JS есть наследование. Можно выстроить цепочку наследования по цепочке прототипов. Особенно хорошо его можно проиллюстрировать для новичков на примере свойства __proto__ в firefox'e.

3) Ну и для примера замыканий я бы что-нибудь другое подобрал. Ну это чисто вкусовщина, а не недостаток.
хм… не увидел у себя описанных недостатков

1. Я не отрицал, а наоборот подчеркивал (4ртый абзац и далее)

2. можно говорить о наследовании прототипов, а не классов. Я это то же писал

3. буду рад увидеть ваш вариант и убрать свой :) О недостатках и достоинствах я не писал вообще, только о разнице :)

у Вас комментарий в стиле «The power of NO» получился %)
2. Ну тогда стоит перевормулировать, так как слова «В JS нет наследования и тем более множественного» как-то слишком уж однозначно говорят о том, что наследования нет, а следующее предложение никак этого не отрицает.

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

насчет The power of NO — большое спасибо, никогда не слышал и не задумывался об этом, с большим интересом прочел статью по ссылке. Думаю, большая доля правды в ней есть и насчет моего комментария также.
Спасибо за статью и на наводку про «замыкания», помогло решить проблему, адекватным и характерным языку способом.
Большое спасибо за статью!
Правда, в примеры долго смотрел — безумно непривычный стиль
Спасибо за популяризацию ДжС! Сам недавно на работе коллегам глаза открывал на его природу.
Но вот ваш стиль расстановки скобок я не понял :)
Чем лучше человек понимает предмет, тем проще он о нем рассказывает. Спасибо :)
В каждом языке наследование понимается по своему, но все же вряд ли на этом одном различие можно построить целую парадигму. Стив Едж назвал это шаблоном проектирования, пусть и универсальным :)
steve-yegge.blogspot.com/2008/10/universal-design-pattern.html

А в целом о распространенных парадигмах можете прочесть у меня:
lisp-univ-etc.blogspot.com/2008/12/blog-post.html
UFO just landed and posted this here
Да, ты прав :)

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

По противоречиям всё просто :)

а) Наследования, как такового нет, т.е. нельзя определить объект и как в C++ сказать class B: public A{...}. Есть прототипы, через которые можно сделать «почти» то же самое, об этом и писал :)

b) Я писал о пример — в примере выше конструктора не было, а далее я привел пример именно с конструктором
>в примере выше конструктора не было, а далее я привел пример именно с конструктором

Там был конструктор 'win', который создал 'vista'… ;)
был :) верно :), и не один, мой очень внимательный читатель, но совершенно не годный, как хороший пример :)
UFO just landed and posted this here
да, спасибо за ссылку

Илья Кантор молодец, респект и уважуха :)
имел честь с ним работать, профи!
>а то не ясно есть наследование или нет

Есть наследование, но чтобы терминологически не смешивать с class-based можно или думать о нём, как об object-based inheritance или как о delegation.
> но чтобы терминологически не смешивать с class-based

Если говорить о цепях наследования — то в классах тоже самое (во всяком случае, в динамических классовых реализациях) — делегация.
Ну, можно прилагательных нужных добавить (2-ое или 3-e сверху или сразу оба), чтоб обозначить свою javascript-овую нишу ;):

object-oriented
....object-based
........prototype-based
............delegation-based

Всё же delegation звучит ближе к PBL чем к CBL, меньше неправильных ассоциаций возникает, если оттолкнуться от Lieberman-а, то у него как раз противопоставляются inheritance vs. delegation. Без затей.
> Ну, можно прилагательных нужных добавить (2-ое или 3-e сверху или сразу оба), чтоб обозначить свою javascript-овую нишу ;)

Ну, если, все-таки, надо выделить «нишу», тогда только 3 ;) Поскольку 2 и 4 (а 1 — априори), допустимы и в языках, где употребляется термин «класс».

> меньше неправильных ассоциаций возникает

Для этих целей, да.

> Без затей.

Ага, чтобы как-то разграничить; создать «свою» «нишу». Если же начнем капать, то там — опять концов терминологии не сыщем ;)
> (замыкания и прототипы)… объясните мне

Было уже много статей, но попробую рассказать кратко (но очень подробно) и простыми словами в этом комменте:

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

Пример:

var a = 10; // глобальная переменная

function b() {
  var c = 20; // локальная переменная
  alert(a + c); // 30
}

В данном случае, функция «b» порождена в глобальной области видимости, и, соответственно, ей доступны как свои локальные переменные, так и глобальные. Однако, переменная «а» является свободной для функции «b» (т.е. переменная «а» не определена в области видимости функции «b»). Не буду вдаваться в подробности и механизм реализации этого эффекта в JS (variable object и scope chain), но главное здесь понять, что функция имеет доступ, помимо своих переменных, к переменным, которые были объявлены в той же области, что и сама функция, а также к переменным из областей стоящих выше в иерархии.

Пример:

var a = 10;
function b() {
  var c = 20;
  function d() {
    var e = 30;
    function f() {
      var g = 40;
      // доступна своя "g", а также 
      // "а", "c" и "е" из областей выше
      alert(a + c + e + g); 
    }
    f();
  }
  d();
}
b();

В принципе, это очевидно, и реализовано практически во всех языках.

При подходе, описанном выше, ни переменная «с», ни переменная «e», ни переменная «g» не будут существовать после вызова функции «b». Т.е. (локальные) переменные доступны только в области видимости, в которой они описаны, а также в областях, стоящих ниже в иерархии.

А теперь главная особенность, которая и позволит создать эффект замыкания. Функции в JS — это обычые (переменные) объекты, которые можно вернуть (после описания) из других функций:

function a(i) {
  var z = 10;
  function b() {
    alert(i + z);
  }
  return b; // возвращаем функцию "b"
}

var c11 = a(1);
var c12 = a(2);

c11(); // 11
c12(); // 12

Т.к. функция «а» возвращает функцию, то переменные с11 и с12 — есть функции. Но! Не просто функции, а функции, помнящие всю цепь областей видимости, начиная от области видимости, в которой они порождены (в данном случае, это внутренняя функция «b»). Т.е. функции c12 и c12 будут помнить область видимости функция «а».

В данном случае, переменные «i» и «z» в отличии от случая, описанного выше (с «с», «е» и «g») живы после того, как функция «а» отработала. Это и есть замыкание (т.е. значения переменных «i» и «z» замкнулись в функции «b», которая затем вернулась из «а» и стала доступна для вызова через переменную c11 (аналогично и с12)).

Поэтому, замыкание — это не только, когда свободные переменные из внешнего scope'a доступны внутреннему, но и тогда, когда они могут быть доступны после того, как функция, порождающая внешний scope отработает.
Да, отлично :)

Я вот думаю, да же не смотря на твой комментарий написать статью на эту тему

более доступную, чем эта

как ты думаешь, стоит?
> как ты думаешь, стоит?

Ну, в принципе, подобных статей уже навалом. Однако, всегда можно рассказать о некоторой теме предмета более развернуто и, если статья массовая, а не академическая, то — как можно доступней, чтобы не отпугивать людей, а наоборот привлекать, показывая, что JS — прост, но очень изящен. К тому же, если чувствуешь потребность написать, — конечно пиши.
все операции с классами/объектами в ооп в большинстве языков являются просто надстройкой над указателями и структурами. и нет совершенно никакой разницы, реализуются классы через прототипы или структуры. нет никакой разницы между явными и неявными конструкторами. и замыкания просто и весело можно реализовывать в C, просто придется дополнительные параметры передавать.

если вы не будете заморачиваться с «парадигмами», то поймете, что между языками программирования в большинстве вообще нет никакой разницы. просто местами отличаются реализации алгоритмов, а сами алгоритмы не меняются.
ну, так вы до байт кода доберетесь или до стека процессора, а там вообще ВСЯ разница теряется, и нет ни какой разницы ООП или нет :)

все языки являются надстройками для создания байт кода :)
> если вы не будете заморачиваться с «парадигмами», то поймете, что между языками программирования в большинстве вообще нет никакой разницы.

Посмотрите Scheme, Prolog, Pure, Agda, Haskell, OCaml. Сравните каждый из них друг с другом, а потом с Delphi, C, C++, Java, C#, и прочими. Разница таки есть.
Оооочень сложно читать. Чувствовалось что вам очень многим хочется поделиться, но кажется, вам не совсем удалось собрать мысли воедино. Или это я перегрелся от обилия работы.
Но все равно спасибо. Начало статьи тронуло чувствительные нотки. Многие действительно относятся с некоторым снобизмом к нашей работе. :( Хотя иногда клиентская часть содержит больше интересных решений чем серверная. Да и по функционалу многие веб-интерфейсы уже доросли до своих домашних братьев.
Выскажусь по некоторым ключевым пунктам:

> Это не означает, что на JS невозможно сделать абстракции, инкапсуляции, наследование или полиморфизма.

Инкапсуляция — строгой инкапсуляции нет, но часто знание, что «так делать нельзя» — является инкапсуляцией. Инкапсуляция — лишь эффект создания черного ящика, его можно и достичь при открытости промежуточных сущностей. Можно замыкать var'ы, делая их недоступными напрямую из вне (хотя, есть реализации с eval'ом, когда их, все же, можно достать).

Наследование — заложено изначально в идеологию языка. Весь язык пропитан (делегирующим к прототипам) наследованием. Как вариант, часто привожу пример — объясните, что здесь происходит: — alert(1.toString());

Полиморфизм — есть изначально (ничто не мешает объявить методы с одинаковым названием, но с разной реализацией для разных объектов; ничто не мешает переопределить одноименные методы).

Не ясно, что имелось в виду под «сделать абстракции», ну да ладно (а вообще — в JS много абстракций).

> Получившийся экземпляр имеет структуру и поведение, жёстко заданные его классом.

Только в статических реализациях, динамических это ограничение не касается. При этом «классы-прототипы» здесь не при чем.

> В JS нет наследования и тем более множественного.

Уже отмечалось. В JS есть наследование — прототипное делегирующее, схожее с динамически-классовым делегирующим.

> а) Наследования, как такового нет, т.е. нельзя определить объект и как в C++ сказать class B: public A{...}. Есть прототипы, через которые можно сделать «почти» то же самое, об этом и писал :)

Я бы сказал, что нет такого синтаксического сахара "… :public A"; само же наследование, естественно, есть. Кстати, слово «почти» — вряд ли может быть однозначно описано, поскольку сложно сказать, что это «почти» в себе содержит.

> Внимательный читатель меня спросит — а где же в этой дьявольской смеси конструктор? Да, здесь его не было.

Терминологию лучше не путать. win, как уже отмечал Zeroglif, есть конструктор (в официальной терминологии JS). На конструктор можно смотреть, как на штамповщик объектов по заданному шаблону.
спасибо, я рад что наше мнение совпадает :)

рекомендую прочитать статью: «The power of NO» почему-то не сомневаюсь что она доставит Вам удовольствие %)
> рекомендую прочитать статью: «The power of NO» почему-то не сомневаюсь что она доставит Вам удовольствие %)

Читал уже :) Рекомендую почитать о психоанализе в целом, и о том, что в одной из типологий (например, информационного метаболизма) можно подразделять людей на «негативистов» и «позитивистов». При этом, это вовсе не означает (ага, здесь снова можно — «ну вот, вы подтверждаете мою теорию :)»), что один негативный, другой позитивный. Здесь можно проводить аналогии со «целью» и «достижением цели (путем к цели)» (в то время, как цель не столь и важна). Негативисты, всего лишь, видят в объекте те свойства, которые в нем не полны (замечают отсутствие свойств). Позитивисты — наиболее отчётливо видят свойства, которые присутствуют в объекте.

Наглядный пример:

— «На небе ни облачка!» или «Неплохая погода!» — фраза негативиста.
— «Небо ясное!» или «Хорошая погода» — фраза позитивиста.

При этом позиция, описанная автором в статье про «зэ пауэр оф НОУ» — практически беспроигрышная. На любую негативистскую фразу можно сказать — «ну вот, вы подтверждаете мою теорию». Что, в психологической теории, является «тонким» (для тех, кто не особо знаком с этим) демагогическим ходом.

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

Другое дело, что нужно различать «упрямство с неосознанной (подсознательной) целью победить в споре». Тогда как более высокой степенью обмена информацией — является дискуссия с нежеланием «поставить ногу на грудь», а найти относительную истину. Именно об этом автор пишет в той статье.
Кстати, психологи рекомендуют не употреблять негативиские фразы (с приставками «не» — «неплохая погода», «на небе ни облачка») на всякого рода собеседованиях, PR и т.д.
Ах, да, прошу прощения, что привожу терминологию и описание, не указав ссылку на саму типологию; если, вдруг, будет интересно — ознакомительная ссылка в Вики — ru.wikipedia.org/wiki/Тип_информационного_метаболизма (это пара наука). И, кстати, одним из аспектов типа, к которому отношусь я в этой типологии, является негативизм — «желание дополнить, улучшить систему, видя в ней недочеты» (но никак не «упрямое отрицание, с целью поставить ногу на грудь»)
спасибо за рекомендацию и всё же поздно, я читал

Кстати, был когда-то негативом, смог исправиться. Путь — просто перестал говорить нет и всё что начинается с не… Мышление стало меняться то же. Сам себя перепрограммировал :)
> Кстати, был когда-то негативом, смог исправиться. Путь — просто перестал говорить нет и всё что начинается с не… Мышление стало меняться то же. Сам себя перепрограммировал :)

Тип не меняется. Исправляться можно лишь в плане слабых функций (у каждого они есть) — т.е. тренировать слабые функции. Если будет один позитивистский подход, то многие формальные возможности системы могут быть упущены (именно поэтому в дуальной паре одни позитивист, другой негативист (прим. «дуальная пара» — пара полного дополнения и поддержки по слабым функциям партнера; наилучшее общение)).

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

В каждом сочетаются оба аспекта (и здесь нет ни «хорошего», ни «плохого») — это всего лишь отбор свойств в объекте — те которые «видны», либо те, которые «пока не видны, но хотелось бы».

Ладно, думаю, оффтоп устраивать не будем ;)
пожалуйста, продолжайте, это интересно )
О-о, боюсь, это тема не одного коммента ;) Да и, собственно, я знаю соционику на любительском уровне (так — интересно, конечно, но не «фанатею», так сказать).

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

В основном, можно задать психотип, описывая его 4 дихотомиями (парами взаимоисключающих признаков). Это:

1. рациональность–иррациональность;
2. экстраверсия–интроверсия;
3. логика–этика;
4. сенсорика–интуиция.

Комбинируя признаки дихотомий, всего выделяют 16 психотипов. Например, «рациональный логико-интуитивный интроверт» (псевдоним для более легкого запоминания — «Робеспьер»), или «иррациональный сенсорно-этический экстраверт» (псевдоним «Наполеон») и т.д.

Суть в том, что какие-то из аспектов человек воспринимает осознанно, и по в этих аспектах он чувствует полную уверенность (и эти аспекты определяют смысл жизнь; это комбинация «программной» (1) и «творческой» (2) функции), а другие аспекты — находятся в зоне комплексов и неуверенности (например, «болевая» (4) функция — это слабое место человека). Так вот, ваша «болевая» функция находится в «программной» у вашего конфликтера (т.е. то, что развито у конфликтера, у вас — вызывает неуверенность и потребность активно защищаться по ней). Т.е. конфликтер осознанно давит на вашу «болевую» (так же как и вы на его). В свою очередь у дуала, ваша болевая находится в подсознательной функции и он берет на себя ответственность (неосознанно) по поддержке вас по этой функции, тем самым дополняя вас (так же, как и вы его). Помимо дуалов и конфликтеров есть есть множество других отношений.

Помимо этих 4 дихотомий есть еще деления, состоящие из 16 признаков Рейнина (здешний питерский математик, который разработал эту теорию, описав это математически); туда, кстати, и входят упоминавшиеся выше «негативизм-позитивизм».

Можно здесь посмотреть: socionika.info/

Так же можно пройти тест и определить свой ТИМ (тип информационного метаболизма): socionika.info/test.html (однако, тесты могут «врать»; человек может (неосознанно) выбирать ответы, которые ему нравится, но не те, которые есть на самом деле)

Описания типов: socionika.info/tips.html

P.S.> надеюсь, не слишком перегружено получилось ;)
С номерами функций путано получилось. Имеется в виду номера функций, так называемой, Модели А, а не моя нумерация дихотомий выше (просто я пронумеровал дихотомии, а потом использую номера функций из Модели А; вот, исправляюсь, уточняю, что это не они :))
удалить комментарий :)
а про чёрную кошку не Конфуций разве?
не знаю, спросить надо :)
т.е. я хотел сказать, что в полном собрании сочинений уважаемого Куна этой фразы нет, но её действительно часто ему приписывают
Вон оно даже как… в любом случае, у него уже спрашивать поздно ;)
даже называют кошкой Конфуция :)

кстати, также кот есть у Шрёдингера, им тяжело встретиться, и легко подружиться :)

интересно, есть ещё животные у великих?
> Ребятам молящимся на парадигму ООП, проснитесь, есть много других парадигм программирования.

Конкретнее надо: речь о Simula-style ООП, на которое молятся, как на божка.
Чего-то я не понял, что тут принципиально нового по сравнению с моей статьей, ну да ладно )

По существу:
В прототип-ориентированных системах (например JS) предоставляется два метода создания нового объекта: клонирование существующего объекта, либо создание объекта «с нуля».

Это не так. Даже создавая объект как obj={} мы всегда используем конструктор Object и его прототип. Более того, если мы этот прототип расширим, то и эти добавленные свойства будут во всех якобы «созданных с нуля» объектах.

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

По существу не вижу, что не так :) Я нигде в статье не отрицал то о чём вы сказали далее:
Даже создавая объект как obj={} мы всегда используем конструктор Object и его прототип. Более того, если мы этот прототип расширим, то и эти добавленные свойства будут во всех якобы «созданных с нуля» объектах.

«с нуля» это образное выражение именно поэтому я употреблял его в кавычках.

До сих пор нахожусь под впечатлением статьи «The power of NO» :)
… он мало того что уже имеет свойства и методы, так еще и не всегда одни и те же (в случае расширения базовых прототипов — вот из-та таких тонкостей я бы не стал использовать выражение «с нуля» даже в кавычках. Потому что уж слишком образное оно получается. И вроде как использовано только для красного словца.

Почему бы не сказать просто: «Все объекты в JavaScript создаются путем клонирования существующих. По умолчанию источником клонирования является базовый объект Object».
И коротко, и корректно.
Ну, клонирование объектов в тексте автора это общий термин для всех прототип-ориентированных языков. В самом JS понятное дело не происходит никакого клонирования, а происходит делегирование от объекта к его прототипу.

Сама же фраза «создание объекта с нуля» некорректна ни в том случае, ни в другом.
>Все объекты в JavaScript создаются путем клонирования существующих
>В самом JS понятное дело не происходит никакого клонирования

Противоречиво вышло. ;) Так всё-таки «cloning» или «ex-nihilo»?
Угу, противоречиво )
Я когда писал первый коммент, смотрел не на ту часть текста, где вот строчки из Википедии, а на ту, где Создание объекта «с нуля» в JS, «это вещь»!
В итоге смешал понятия из прототип-ориентированных языков вообще и из JavaScript конкретно.

Правильная фраза видимо должна звучать так:
«При создании любого объекта в JavaScript мы связываем его с объектом-прототипом при помощи функции-конструктора, таким образом среда исполнения способна выполнять диспетчеризацию вызовов методов (или поиск нужных данных) в созданном объекте к объекту-прототипу. По умолчанию конструктором является Object, а прототипом — Object.prototype»

Однако, боюсь что такая фраза уже теряет всю легкость и простоту )
Думаю, автор просто хотел показать, как ему удобно использовать инициализатор объекта, 2 фигурных и вуаля — объект с нуля. Наследуемые свойства остались за кадром.
ага, либо показать разницу, между порождением объектов с помощью пользовательских конструкторов, и без их использования
На самом деле, когда начал конкретно вникать в JS полтора года назад, прототипы показались страшной вещью, но сейчас они мне больше нравятся, чем стандартное ООП.
> прототипы показались страшной вещью, но сейчас они мне больше нравятся, чем стандартное ООП.

Так а что? — В динамических классовых языках (типа Python и Ruby) — тоже самое (цепь классов, добавление нового слота в любое из звеньев цепи, тут же отражается на объектах, порожденных от (конструктора) этого звена, либо звеньев, находящихся ниже в иерархии)
Sign up to leave a comment.

Articles