Pull to refresh

Comments 193

Со многим согласенн. На мой взгляд, приватные методы и свойства более менее безопасно применять реализуя известные паттерны, к примеру Singleton или Factory. Еще довольно удобно туда прятать неймспейсы. Но этим, пожалуй, и исчерпываются варианты когда их следует применять, в остальных случаях можно обойтись пабликом.
Где вы такое применение видели? Я имею ввиду создание переменных и методов внутри конструктора? Они же вообще нигде доступны не будут.

А по поводу объективности применения приватных методов — я их использую, когда не хочу их видеть в дебаггере. Больше необходимости в них нет, т.к. защитить код вы всё равно не можете.
И экономии в таких случаях нет, так приходится писать method.call( this )
Почему не будут доступны?? А как-же «привелигированные» методы определенные внутри конструктора.
Т.е.:
function make_obj(a, b) {
//Private
var prop1 = a;
var prop2 = b;

method1 = function(){...}
method2 = function(){...}
methodN =…
//Public
this.publicMethod1=function(){… use private here...}
this.publicMethod2=function(){… use private here...}
this.publicMethodN=function(){… use private here...}
}

Под защитой кода тут имеется ввиду защита от доступа к переменным и методам, что в некоторых случаях избавляет от ошибок.
И всё рассыпиться при наследовании.
И всё-таки, откуда откопали такие примеры, где в конструкторе описывается весь класс?

Как сказано выше, оправдано только для singleton и lazy initilization.

По мне всё что вы привели, это уровень чайника. И обсуждать оправдано или нет в реальных проектах… всё-таки не стоит.
Почему рассыпется? Не понятно… Я сам против «приватнах» методов, но за методы определенные внутри конструктора. Т.е. на мой взгляд, следующее имеет место быть:

function Obj()
{
this.publicMethod1=function(){…}
this.publicMethod2=function(){…}
}

А откуда это откапывается, я Вам скажу. Мной это было почерпнуто из набл ув. Д. Котерова:
dklab.ru/chicken/nablas/39.html#list9

В прототип же выносятся как правило статические методы, которые используются без создания объекта.
По той же ссылке что вы дали, читайте пункт Наследование

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

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

function NewObj() {}
NewObj.prototype.nonStaticMethod = function ...
NewObj.staticMethod = function ...
Та нет, это я перепутал. Конечно же статические методы определяются указанным вами способом.

Про прототипы там ниже тоже указано, что так оптимальнее. А я выбираю описание внутри конструктора, за изящность, пока проблем с производительностью не наблюдал…
А в чём изящность (кроме возможности создавать приватные свойства)?
Ну во-первых некая схожесть с классическим синтаксисом описания класса (лично я её вижу). А во-вторых, имя класса хранится ровно в одном месте.

Признаю, что это всё субъективно, и производительность дороже.
Не рассыпется если сделать так:

function make_obj_extended(a,b){
this.constructor.prototype.constructor.call(this,a,b);
}

или

function make_obj_extended(a,b){
make_obj.constructor.call(this,a,b);
}

В случае если наследование организовывается с помошью YUI:

function make_obj_extended(a,b){
make_obj_extended.superclass.constructor.call(this,a,b);
}

Конечно нет необходимости описывать весь класс внутри конструктора — как было указано в статье, это стоит слишком многих ресурсов, однако, есть такая возможность. И это хорошо. Т.к. позволяет реализовывать различные паттерны.
А вы пробовали?
Давно как-то крутил такие трюки, там потом проблемы this.
Хотя бы то, что такие конструкторы вызываются при определении наследования, побуждают меня так не писать.

В общем, при реализации каких-то паттернов так может и имеет смысл писать. В реальности же я так никогда не делал.
И лично считаю такое bad coding style.
Я не просто пробовал но и пишу так всевремя. Никогда никаких проблем с this небыло.
На работе в качестве корп кодинг стиля:

function obj_extended(a,b){
obj_extended.superclass.constructor.call(this,a,b);
}

Это первые строчки любого класса. Это вовсе не означает что все методы тут-же объявляются внутри конструктора, однако позволяет быть уверенным в том, что при наследовании нового класса он будет корректно проинициализирован.
obj_extended.superclass.constructor.call(this,a,b);
Про такую конструкцию я не спорю.

this.constructor.prototype.constructor.call(this,a,b);
Вот эта точно работать не будет при двойном наследовании.

При двойном — нет, однако, мне кажется что двойное наследование довольно редко встречается.
ИМХО, лучше использоваться decorator для добавления новых свойств и методов Классу наследуясь от одного, а не двух Классов. Хотя это больше про кодинг стайл, а тут уж у каждого свои предпочтения.

ПС: хорош или плох кодинг стайл, лучше когда он есть, чем когда его нет.
декоратор для добавления новых свойств это круто
а что вас смущает?
только терминология
определение "структурный шаблон проектирования, предназначенный для динамического подключения дополнительного поведения к объекту" реализуется совершенно иначе, и добавление новых методов противоречит сути декоратора
*совершенно иначе, чем хотелось бы думать, читая книжки по диагонали
Действительно, я не прав, приношу извинения:)
ух ты. а я ожидал срача на 5 страниц. спасибо :)
Блииин, что же вы творите, тут же при каждом создании объекта во-первых, будут заново создаваться ф-и (this.publicMethod1 и тд), во-вторых, они будут удерживать в замыкании ссылку на объкт переменных ф-и make_object, все это сильно увеличивает расход памяти.
Вас может это удивит, но я это прекрасно понимаю:)
И это отлично что вы это понимаете, т.к. можете использовать свойства и методы только там где это оправданно. К примеру, это оправданно при создании Singletonов т.к. объект по определению один и нет временных потерь по созданию большого количества объектов и соответственно нет больших потерь памяти.
Из-за таких топиков я и люблю хабр :)
> абстракция, полиморфизмом, наследованием и инкапсуляция… всего лишь особенности реализации ООП в определенных языках, а вовсе не догма.

Вы уверены? т.е. Вы сможете привести пример ООП программы, даже без абстракции (набора объектов)?
У вас несколько искаженное цитирование. Я имел ввиду, что наличие всех этих концепций в языке одновременно не является обязательным условием для того, чтобы назвать его объектно-ориентированным.

Также реализация этих вещей в конкретных ЯП может варьироваться начиная от строго формальной (private, public, protected), до идеологической (в JS мы можем работать с объектами так, как будто это «черные ящики», но можем и не делать этого. Подход определяется задачами проектируемой системы, а не формальными инструкциями языка).
> реализация этих вещей
хотел сказать «реализация инкапсуляции»
а что же тогда является обязательным условием?
Наличие объектов (имеющих состояние) и возможность их взаимодействия )

Вот, можно почитать мнение автора ООП на этот счет — http://userpage.fu-berlin.de/~ram/pub/pub_jf47ht81Ht/doc_kay_oop_en.

Есть там интересные пассажи, вроде этого
The term «polymorphism» was imposed much later (I think by Peter Wegner) and it isn't quite valid
даже «автор ООП» аккуратно вставил «quite». но Вы считаете, что только абстракция? окей. есть я, банкомат и деньги. зачем мне обращаться к банкомату и авторизовываться, не легче ли мне просто взять деньги? именно по-этому а) мои знания о системе ограничиваются банкоматом б) деньги инкапсулированы в банкомате
depp прав. ООП про передачу сообщений, а не про мантру «наследование, инкапсуляция, полиморфизм». То бишь, через первое можно выразить второе, а через второе выразить первое очень сложно и костыльно (смотрим костыли для жабы, вроде интырпрайзных продуктов, осуществляющих message passing).
в какой-то степени, да, прав. эта степень, правда, слишком крута, чтобы находиться на одной полке с высказываниями навродя «Также к плюсам можно отнести экономию на слове this».

я вот обрисовал ситуацию с тремя объектами, а не ты, не он ответить: «да хуй с ним, с банкоматом, главное чтобы деньги.взять(100) работало» — не решаетесь. прокомментируешь?
я бы ответил чего-нибудь, но нифига не понял смысла этой метафоры с банкоматом :)

> есть я, банкомат и деньги.
ок — 3 разных сущности.

>зачем мне обращаться к банкомату и авторизовываться, не легче ли мне просто взять деньги?
здесь не понял, это ирония или реальный вопрос? конечно надо авторизоваться, вставлять карту и вводить ПИН — иначе как деньги-то получить?

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

> вставлять карту и вводить ПИН — иначе как деньги-то получить?
это не инкапсуляция?

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

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

Замыкание позволяет убрать все лишнее из глобальной области видимости. И вот с помощью него получаем инкапсуляцию.
в SpiderMonkey вплоть до версии 1.7 можно воздействовать на внутренние var'ы посредством передачи вызывающего контекста в eval
> а что же тогда является обязательным условием?

Ничего, ровным счётом. Любая реализация вправе вносить любые коррективы, если они технологически и идеологически обоснованы.
я Вас правльно понял, что можно написать язык, который будет «идеологически» уметь только числа от ноля до пяти складывать — и заявить, что язык поддерживает парадигму ООП, потому что «любая реализация вправе вносить любые коррективы»?
Демагогию отключите (и кнопкой минус не увлекайтесь ;)).

> я Вас правльно понял

Да нет же, абсолютно не правильно, извините :).

> язык, который будет «идеологически» уметь только числа от ноля до пяти складывать — и заявить, что язык поддерживает парадигму ООП

Демагогия. Она здесь не уместна. Вы же понимаете, о чём я говорю.
понимаю, но меру тоже надо знать. демагогически :) я не вижу конфликтов между моим и Вашим утверждениями.

вот человек попытался нам доказать, что в JS-объектах все методы должны быть наружу, прибегая ко всяким модным словам: «ООП», «наследование», «инкапсуляция» и т.д. но не раскрывая их сути. суть-то у скрытия данных и логики явно не в «экономии на слове this при доступе к свойствам в методах», правда?

или не упоминать умные слова, или вместо попыток «объективно рассмотреть достоинства и недостатки такого подхода» писать «имхо».

а кнопка минус у меня любимая, когда люди авторитетно утверждают, что можно приготовить яичницу, не разбив скорлупы ;)
> суть-то у скрытия данных и логики явно не в «экономии на слове this при доступе к свойствам в методах», правда?

Вообще, суть инкапсуляции весьма относительна. Никакое предположение не будет истиной в последней инстанции. Кстати, в чём её суть видите Вы?

> а кнопка минус у меня любимая, когда люди авторитетно утверждают

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

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

без абстракции — абсолютно нельзя (всё программирование — есть абстракция и усиление её при прогрессе). Насчёт ООП, — изначально то, о чём сказал я в этом треде — если какая-то реализация вносит корректировки в изначальную модель и обосновывает это — есть ли смысл брать на себя ответственность за утверждения, что «должно быть так и не иначе»? ;)

> насчет Ваших познаний JS мне ничего не известно. а что, не должно бы?

да нет, знаете Вы или нет, по сути не имеет значения, просто Вы сказали, что любите ставить минус тем, «кто авторитетно что-то заявляет»; я тоже считаю, что «важен авторитет истины, а не истина авторитета»; в ключе же JS, да я могу ответить компетентно.
> без абстракции — абсолютно нельзя
замечательно

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

> да я могу ответить компетентно
расскажите мне, пожалуйста, по какой причине все, нужные и не нужные, методы всех объектов должны «торчать наружу»?
> я тупо пытаюсь по-хорошему разобраться в ООП, можете смеяться

делать нечего больше, желание разобраться — это очень хорошо.

> ООП предоставляет больше возможностей, чем прототипирование

Я предлагаю попробовать найти очень большие отличия между, скажем, Python'ом (который слывёт «ООП-ее некуда языком») и JS. Проанализировать их модели (а главное (самое главное) — механизмы) наследования, инкапсуляции и т.д. Если Вы найдёте эти большие отличия, пожалуйста, напишите мне, мне будет интересно.

> расскажите мне, пожалуйста, по какой причине все, нужные и не нужные, методы всех объектов должны «торчать наружу»?

Инкапсуляция — является «сахаром», однако, не основой ООП. Иногда знание, что «так делать нельзя» — есть инкапсуляция (опять же, можно посмотреть инкапсуляцию в Python'e). Подход к ООП-реализациям (коих может быть множество, опять же — если будет обоснование и целесообразность этих особенностей и нововведений), включая сущность инкапсуляции, не должен быть параноидальным. Инкапсуляция — это дополнение, но не главная суть, не ядро. К примеру, обычные функции с точки зрения абстракции являются инкапсулирующими сущностями — человек знает, как вызвать функцию Math.round(...), но реализация её — абстрагирована и инкапсулирована от использующего её (при этом никаких private, protected т.д. здесь не фигурирует).

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

ну, вообще, я примерно то же самое написал ;)
ООП на функциях и массивах: ;-)

var person_talk = function (person) {
alert(«Hi, I'm » + person[0]);
};

var person_fight = function (person, target) {
alert(person[0] + ": I have no battle skills, so I run away from " + target[0]);
};

var doctor_heal = function (doctor, target) {
alert(doctor[0] + ": I spell heal on " + target[0]);
};

var mage_fight = function (person, target) {
alert(person[0] + ": I spell fireball on " + target[0]);
};

var talk = function (person) {
person[1](person);
};

var fight = function (person, target) {
person[2](person, target);
};

var heal = function (doctor, target) {
doctor[3](doctor, target);
};

var Person = function (name) {
return [name, person_talk, person_fight];
};

var Doctor = function (name) {
var p = Person(name);
p.push(doctor_heal);
return p;
};

var Mage = function (name) {
var d = Doctor(name);
d[2] = mage_fight;
return d;
};

var person = Person(«Barak Obama»),
house = Doctor(«House M.D.»),
aibolit = Doctor(«Aibolit»),
mage = Mage(«BlackMagic»);

talk(person);
fight(person, mage);
fight(mage, person); // специализация
heal(house, person);
fight(house, mage); // наследование
talk(mage);

спасибо за развернутый ответ, но, имхо, сахар — не сахар, а с жестким сокрытием объект выглядит гораздо приятнее.
Я где-то слышал, что Linux при том, что он написан вперемешку на Asm и C(не С++), является хорошей ООП программой. Парадигма на то и парадигма, ее можно, с некоторым извращением, применить к любому ЯП. Мне вот интересно, а как по вашему можно запретить писать ООП код в языке =)?
Это уже откровенное хамство. Может хватит обвинять меня в том, что я не делал?

Фразу про «экономию на слове this при доступе к свойствам в методах» вы уже столько раз процитировали, как будто она вообще единственная и ключевая в статье. Хотя этот момент упомянут вообще вскользь, с ремаркой «также к плюсам можно отнести».
> Невозможно получить доступ к свойству объекта с помощью строкового литерала, например вот так this[(a > 2? 'max': 'min')]
> Казалось бы мелочь, но неприятно.

> Объекты с приватными свойствами сложнее в отладке.

> При эмулировании приватных свойств в JS, нам придется везде в коде добавлять или убирать this. перед обращением к свойству.

Я предпочитаю раскладывать объект на две составляющих — никаких проблем ни с отладкой, ни с переносом public/private свойств. Чего и Вам советую ;-)

Концепция подхода описана тут: code.google.com/p/nulljs/wiki/HowtoPrivateMethods

прикольный велосипед
Какая жесть :)

У вас там во-первых два лишних return: «return Private(this, new Foo(x))» — потому что return в конструкторе вообще игнорируется, достаточно написать просто «Private(this, new Foo(x))», и в связи с этим «return pub» в функции Private (мы и так работаем с объектом pub по ссылке, возвращать его нет нужды).

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

Особо торкающим побочным эффектом является то, что мы можем иметь в таком «как бы объекте» (который состоит из двух других) два свойства priv_x — публичное и приватное одновременно, причем они естественно будут независимы друг от друга, так как по факту принадлежат разным инстансам. По человечески очень жаль программиста, которому придется отлаживать такой код (и которому сходу никто не будет объяснять, как именно этот велосипед работает).
> return в конструкторе вообще игнорируется
нет, только приводится к Object'у. например, вот
ru.wikipedia.org/wiki/Одиночка_(шаблон_проектирования)#.D0.9F.D1.80.D0.B8.D0.BC.D0.B5.D1.80_.D0.BD.D0.B0_Javascript

> жаль программиста, которому придется отлаживать такой код
я тоже весьма-таки удивился подходу, но его достаточно один раз понять — и дальше будет обычный дебаг, сложность которого зависит только от того, что на этом каркасе написано
Нет, ничего там не приводится. Работает, только если то что мы возвращаем — уже объект. Попробуйте что-то типа:
var foo = function(){this.b = 5; return 6;}
var o = new foo();
alert(o.b);

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

var foo = function(){this.b = 5; return {a: 6};}
var o = new foo();
alert(o.b); // undefined
alert(o.a); // 6

Вывод: если конструктор объекта возвращает (любой) другой объект — то this-объект, созданный конструктором, теряется.
> если конструктор объекта возвращает (любой) другой объект — то this-объект, созданный конструктором, теряется.
> Работает, только если то что мы возвращаем — уже объект.

По моему эти фразы аналогичны :)
> У вас там во-первых два лишних return: «return Private(this, new Foo(x))»

Так-то оно так, да не совсем ;-) Тынц: var bar = Foo.call(new Bar(«some-value»), 333);

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

Это вопрос эффективности реализации JS, имхо, а не языка как такового. Кстати, JIT вполне может помочь в этом вопросе.

> можем иметь в таком «как бы объекте» (который состоит из двух других) два свойства priv_x

Можем, конечно! «даже с помощью первоклассных инструментов можно делать г*веные вещи». ;-)

Я просто показал концепт, который позволяет не заморачиваться на локальные переменные, не плодить кучу локальных замыканий в явном виде, а писать «по-старинке» через prototype, ничего кардинально не меняя в коде, но получая при этом требуемый эффект приватных мемберов «класса».
> Это вопрос эффективности реализации JS, имхо, а не языка как такового. Кстати, JIT вполне может помочь в этом вопросе.

Вопрос эффективности реализации JS в различных браузерах — это один из ключевых вопросов при разработке клиентских приложений под веб, в текущих реалиях. Супер красивый и логичный внутри, но приводящий к 0.5-1 секундным подвисаниям на каком-нибудь нетбуке код — нафиг никому не нужен.

Вот, взгляните, статистика по использованию браузеров www.liveinternet.ru/stat/ru/browsers.html?period=week
IE 6-8 в сумме по-прежнему держит более трети рынка. О какой JIT может идти речь?

> Супер красивый и логичный внутри, но приводящий к 0.5-1 секундным подвисаниям на каком-нибудь нетбуке код — нафиг никому не нужен.

Ок, план Б: рассмотрим браузерный JS как target-платформу и сделаем небольшой кросс-компилятор из красивого и логичного JS в некрасивый но эффективный JS для браузера ;-)
зачем «план Б»? «0,5-1 секундное подвисание» в процессе работы будет при любом подходе, поскольку если надо что-то сделать, то это надо сделать, если надо сделать мильён операций — надо сделать мильён операций. а при инициализации 0,5-1 секунд не особо смутит пользователя, особенно когда страница 5-10 секунд грузится, на десктопе приложения за секунду тоже не открывается, и, если приложение открывается меньше, чем за пол-минуты, никто особо не жужжит.
Я, например, как IT-шник знаю, что процессор моего компьютера имеет тактовую частоту в несколько (2-3 в среднем) Ггц, что приблизительно означает выполнение нескольких миллиардов операций в секунду.

Как пользователь ПК, я желаю, чтобы реакция на все мои рядовые действия (не связанные с расчетом мат. моделей турбулентности, 3D сцен и т.д.) была мгновенной, что означает задержку не более 100мс в худшем случае. Я не хочу тратить свое личное время (которое невозможно вернуть назад ни за какие деньги) на ожидание окончания процессов в железяке.

Если создатели приложений, которыми я пользуюсь, ради своих архитектурных изысков накидывают на эту задержку ничем не обоснованные 200, 500 или 1000мс — я начинаю вспоминать разные нехорошие слова.

зачем же тогда появились высокоуровневые языки программирования, почему не зазорно использовать C++ и C#? в таком ключе не стоит думать не то, что бы об операционной системе с графическим интерфейсом, даже ASM, я так понимаю, будет злом в сравнении с машинными кодами.
Меня как пользователя не интересует абсолютная скорость выполнения, меня интересует визуально заметная задержка.

Если приложение, написанное на ASM выполняется 5мс, а на C++ за 25мс — то и хрен с ним, несмотря на то, что разница пятикратная, на глаз она не заметна.

Вот если оно выполняется 250мс — это уже как-то не хорошо.

Я знаю, как писать быстрые приложение на высокоуровневых языках (по крайней мере на тех, которыми владею), и частью этого знания как раз поделился в статье.
а может, бросить Вам эти высокоуровневые языки, для них 250мс на выполнение сложной операции является допустимой величиной, да перехойти на ASM — добьетесь экономии измеримых 225мс на счет месяца своей работы!
А может я как-нибудь сам решу, какой язык использовать для разработки и сколько времени на нее тратить?

Вам кстати желаю того же — пишите на чем хотите, с использованием любых конструкций и парадигм. Не слушайте всяких дураков вроде меня.
ну конечно же, сам. я только посоветовать хочу. в ASM не надо никому доказывать, что инкапсуляцию злые дяди придумали: знай себе JMZ, да AX/BX переключай. и скорость выполнения у него фантастическая.
Ваше упорство в приписывании мне утверждений, которых я не делал, и в мастерском опровержении их же наводит на мысль, что у вас слишком много свободного времени или вы просто тролль.
список таких утверждений, пожалуйста, в студию
> не надо никому доказывать, что инкапсуляцию злые дяди придумали

Я хоть где-то (в статье или комментах) писал, что инкапсуляция (как концепция, а не в рамках JS) — это плохо и ее придумали злые дяди?

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

видимо, это все объективные достоинства. однако Вы потратили много времени, показывая недостатки заслуженной концепции:
Это не так сложно (договориться), как может показаться. — я спросил: «а зачем договариваться, когда можно нормально написать?» — Вы проигнорировали;
деньги в банкомате закончились — имхо, epic fail, и Вы снова проигнорировали следующий коммент, зато назвали меня троллем;
Если не хотите, чтобы какой-то объект вызывал validateWith другого объекта — так не вызывайте — неужели программисты, поколение за поколением, ошибаются, а Вы срываете маски? тот же Ваш PHP не всегда знал, что такое объекты, однако, они в нем почему-то появились, а потом зачем-то появилось и ключевое слово private.

и тут же бездоказательные «я не против». толку с того, что они черным по белому? Вы занимаетесь именно тем, что противопоставляете себя злым дядям.
Написали бы просто сами про объективные достоинства вышеупомянутой инкапсуляции в JS. Интересно же.
Ну как же ж, очевидный плюс явной инкапсуляции в JS — невозможность достучаться туда «куда не следует» снаружи (из прикладного кода), чем гарантируется усточивость инкапсулированного компонента к внешним воздействиям.
Ну, будет у нас с одной стороны всем доступный this.x, а с другой типа спрятанный this.getX() и чего? Больше буков, замыкание и лишний вызов спасают мир от какой страшной опасности? Теоретически вы чётко обозначаете «очевидный плюс», но насколько одна структура удобнее и полезнее другой на практике… На мой взгляд простая инкапсуляция в объекте — идеальный вариант для быстрых компактных скриптов. А всякие там private-public-protected оставим для поболтать. ;)
суть не в том, что значение x можно получить только через getX, а в том, что его не надо получать, и вообще не надо знать, что оно есть. есть методы do1 и do2, а что внутри — без разницы (пока работает).
В чём прЭлесть работы с 'do1' vs. 'x'?
в том, что с x работает do1. еще do1 может работать с y, z, q, w и e, а мы будем знать только про do1.

взаимосвязь между объектами должна строиться не на том, что у obj есть x, а основываясь на целях существования obj.
опять же, должна не в плане, что должна и точка. должна в плане удобнее
Не обижайтесь, но вода. Пример на js в студию.
function Car() {
	var dublicate = this; // this в таймере совсем не тот
	var speed = 0; // и у пешехода есть только одна возможность изменить это свойство :)
	var maxSpeed = 120; // это нужно снаружи?
	var dSpeed = 10; // это нужно снаружи?
	var going = false; // может быть полезно снаружи
	var stoping = null; // может быть полезно снаружи
	// var mileage = 0; // реализовывать не буду, но менять снаружи это явно не положено
	
	this.go = function() {
		// газ
		if (stoping) onStop();
		if (going) return;
		going  = true;
		speed = 10;
	};
	
	this.stop = function() {
		// тормозим
		if (!going || stoping) return;
		stoping = window.setInterval(stopIterate, 10);
	};
	
	this.faster = function() {
		// быстрее
		if (stoping) return;
		if (speed + dSpeed <= maxSpeed) speed += 10;
	};
	
	this.slower = function() {
		// сбавляем скорость
		if (stoping) return;
		if (speed - dSpeed > 0) {
			speed -= 10;
		} else {
			speed = 0;
			going = false;
		}
	};
	
	function stopIterate() {
		// зачем светофору этот метод?
		dublicate.slower();
		if (!going) onStop();
	}
	
	function onStop() {
		// встали
		window.clearInterval(stoping);
		stoping = false;
		going = false;
	}
}
ойой, тестирование явно не пройдет, но суть уловить очень легко
Понятно. То есть вам просто удобнее создавать несколько методов непосредственно в объекте, чем создавать свойства там же и методы один раз в прототипе. В вашем случае свойства хранятся в объекте активации конструктора (вы как бы не замусорили сам объект), но при этом вы наполняете каждую инстанцию заново создаваемыми однотипными методами (замыканиями), что не оптимально в отношении создания функций и вряд ли удобно в отношении организации под-над-структур (наследование).
> создавать несколько методов непосредственно в объекте, чем создавать свойства там же и методы один раз в прототипе

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

> this.x, а с другой типа спрятанный this.getX()

в примере есть maxSpeed, dSpeed, stopIterate и прочие параметры, у которых нету и не должно быть ни сеттеров, ни геттеров.
> в примере есть maxSpeed, dSpeed, stopIterate и прочие параметры, у которых нету и не должно быть ни сеттеров, ни геттеров

ну я уже писал выше — данный момент больше вытекает в понятие абстракции (и дальше можно продлить в инкапсуляцию) — обычная функция Math.round(...) — будет использовать тысячи внутренних переменных (и maxSpeed, maxSpeed, и dSpeed, и ещё сто штук) — это есть абстракция (и, как следствие, инкапсуляция), чёрный ящик (никаких private, protected здесь не видно, однако, они, естественно, вполне хороших синтаксический сахар). Сама же жёсткая инкапсуляция — только в головах — те, кто будут использовать Ваши классы — вполне могут открыть исходники и поменять private на public (если захотят). С другой стороны, может быть откомпилированный сервис, и к исходникам доступа нет, тогда минимальный интерфейс наружу (со скрытыми тысячами вспомогательных сущностей, которым нельзя присвоить значение прямо (возможно, dSpeed вычисляется по хитрой формуле внутри)) — это хорошо (система будет стабильней), но самое главное — осознавать, что это дополнение, сахар, но не суть ООП.
> данный момент больше вытекает в понятие абстракции
верю, но холивар идет по теме «должно ли все наружу»

> вполне могут открыть исходники
конечно, но когда человек правит код класса, с инстанциями которого он должен только работать — он (по условию задачи) осознает, что делает что-то не то

> откомпилированный сервис, и к исходникам доступа нет
да будет, сколько приложений взломанных, а они все откомпилены

> осознавать, что это дополнение, сахар, но не суть ООП
верю, но, имхо, лучше делать вещи удобные, чем не стабильные
> верю, но, имхо

ну, «имхо», это хорошо, к тому же, это непротиворечивое «имхо», а вполне (повторю), технологически и идеологически обоснованный «сахар»
Нету и не должно? Забавно. Значит я могу так вообще туда массив кинуть (а собственно почему и нет, я считаю что скоростей может быть много) или еще один объект, который будет представлять собой скорость, с двумя методами getKMH и getMPH, и буду прав.
> Нету и не должно?
«опять же, должна не в плане, что должна и точка. должна в плане удобнее» — в комменте рядом написал.

> который будет представлять собой скорость, с двумя методами getKMH и getMPH, и буду прав
а разве нет?
Да я бы не сказал, что это удачное решение… Особенно, если мы в нашем уютненьком классе работаем со скоростью как чем-то абстрактным и скалярным. Думаю кроме NaN мы так ничего и не получим в итоге.
> Думаю кроме NaN мы так ничего и не получим в итоге.
NaN очень тяжело получить, когда все операции над переменной speed производятся в одном объекте.

nearestCar.speed = -50;
зато вот так нельзя сделать
Посмотрите на свой код выше, если я там буду использовать объект Speed, будет у меня все так прекрасно? Нет.
почему нет? в чем, рассматривая этот пример, для speed разница между Number и Object? можете пример привести
> вряд ли удобно в отношении организации под-над-структур

ну, есть некоторые проблемы

> вряд ли удобно в отношении организации под-над-структур (наследование)

да, есть проблемы
> идеальный вариант для быстрых компактных скриптов

да, все надо применять с умом
можете мои комменты (на этой странице) посмотреть, наврядли я что-то мнго большее скажу
Можно я напишу?

Допустим у меня есть такой замечательный объект как Foo, у которого есть не мение замечательный метод getBar, и приватное свойство Bar. И вот ведь так получаеца, что пока мы не запросим этот самый Bar, нам плевать что его собственно нет (Lazy loading).

Как я представляю данную ситуацию без инкапсуляции:
if(foo.bar == null)
foo.bar = new Bar()
// и еще с десяток строчек сборки этого самого Bar-а.

и так везде где мне потребуца Bar, думаю код который вытаскивает нужны нам Bar, выглядит лучше когда он выглядит так:
var bar = foo.getBar();
// что-то делаем с Bar


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

Только теперь давайте представим, что свойствами этого класса начинают пользоватся другие компоненты. Вот к примеру я встречал замечательный хак, который при обработке валидации формочки, лез в класс и в некоторых ситуациях убивал ошибки, которые скидывались в this.errors, и вроде бы как валидация была пройдена успешно. Почему было так следано — а очен просто — это был самый простой и быстрый способ решения проблемы.

Если есть еще вопросы — обращайтесь.
> var bar = foo.getBar();

Не миксуйте понятия инкапсуляции и композиции.

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

Есть жёсткая инкапсуляция (aka private, public и др.) — хорошо, нет — тоже неплохо (своя реализация). Кто называет инкапсуляцию основой ООП — не прав, поскольку, повторю, инкапсуляция вытекает лишь из усиления абстракции (но никак не из паранойи), а абстракцией является ровно всё в программировании (даже при программировании на ассемблере и в hex-кодах — ведь hex-коды — это уже абстракция (и инкапсуляция) сигналов процессору — человеку на надо знать, как эти hex-коды реализованы внутри).
Я прекрасно понимаю разницу между композицией и инкапсуляцией, а вы вот не поняли то, о чем я хочу сказать, ок, другой пример:

Тот же класс Foo, у которого есть метод getSomething, который собственно что делает — берет свойство somethingValue и умножает его на somethingCoeficient.
> а вы вот не поняли

да что Вы? ;) понял-понял.

> Тот же класс Foo, у которого есть метод getSomething

и что? getSomething — обычное свойство-геттер, возвращающее вычисленное значение на основе ста внутренних переменных. Здесь люди спорят (зачем-то ;)) — должны ли быть эти сто переменных недоступными напрямую, или же не обязательно. Кто-то зачисляет это в основу ООП (тогда как это основа абстракции), кто-то — нет. При этом, ещё раз повторю, любая реализация, если захочет и это будет полезным и нужным — может вносить любые коррективы. Private, public, protected — есть эти коррективы, какая-то реализация захотела их внести, посчитав достаточно удобным «сахаром» — все это прекрасно осознают. Я ратую за то, что смысла что-то жёстко категорично отстаивать в данном случае — нет, поскольку не мы создатели этих систем, мы их анализируем, смотрим плюсы и недостатки, не так ли?
Я считаю что язык должнен быть гибким но в тоже время очень жестким и не позвалять глупости человеку который на нем пишет. К примеру все свойства в классах — в прайват и к ним или явные или неявные геттеры и сеттеры. К примеру пишем мы foo.bar = foobar — по сути, язык наш понимает это так, словно мы бы написали foo.setBar(foobar).

Глобальная область видимости — вообщем-то неплоха, за исключеним того, что у некоторых разработчков появлятся соблазн делать грязные хаки, потому-что лень или нет времени что бы сделать правильно.
> Я считаю

ну вот и замечательно, «имхо» никогда не возбраняется

> жестким и не позвалять глупости человеку

думаю, лучше тоже в «имхо» засчитать ;) к примеру, Python не позволяет расширять стандартные классы, а Ruby (и JS) — позволяют — кто тут прав? Никто, и в то же время — каждый по своему (по своей реализации). C++/Java вообще не позволяют («жёстко, без глупостей человека») — они, может быть, правы? — и да, и нет — особенность реализации, не более.
Смотря с какой стороны посмотреть, но питон поступает плохо — чем встроенный класс отличается от того, который написан мною — да впринципе ничем (это с точки зрения разработчика), так почему я не могу применять к нему наследование. Финальные классы это конечно хорошо, но не до такой степени.
> так почему я не могу применять к нему наследование

да нет, немного не об этом речь, наследоваться-то, естественно, можно, речь о расширении базовых классов новыми свойствами и методами (хотя, с этой точки зрения, С++ и Java получаются вообще плохие? ;) естественно, нет, просто у них свой реализация — статичная, жёсткая).

Возвращаясь к «жёсткой инкапсуляции при описании классов», — можно взглянуть на реализацию в Питоне:

class A(object):

    def __init__(self):
        self.__a = 10

    # только для примера
    def get_a(self):
        return self.__a

a = A()
a.__a # ошибка, __a - private
a.get_a() # 10, геттер для private __a
a._A__a # вот он и "private" __a

Т.е., опять же, свой взгляд на private — protected — public.
Итого, мы имеем конфликт интересов:
— с точки зрения пользователя, приоритет №1 — эффективность выполнения кода (aka скорость реакции железяки и минимизация времени на получение результов).
— с точки зрения разработчика, приоритет №1 — эффективность разработки и сопровождения кода.

Кто виноват? Что делать? (И кого бить?) ;-)

P.S. Добавил маленький бенчмарк, если интересно — можете погонять тесты (V8 жжот!, оверхед на лишний call ~= 2ms и это под VirtualBox). code.google.com/p/nulljs/wiki/HowtoPrivateMethods

У вас подход к пользователи с точки зрения компьютерщика. Это в корне не правильно. Приотритет №1 пользователя — чтобы задача была выполнена. А условия выполнения задачи — это уже вторично. Если у вас есть возможность использовать гугл мапс с любого телефона сегодня, имя задержки по 1-2 секунды, либо через 10 лет, но имея задержки по 0.1-0.15 секунд — что вы выберите?
Вы не вникли в контекст дискуссии.

«Если создатели приложений, которыми я пользуюсь, ради своих архитектурных изысков накидывают на эту задержку ничем не обоснованные 200, 500 или 1000мс — я начинаю вспоминать разные нехорошие слова.» © depp
А вы уверены, что они ничем не обоснованы? Архитектурные изыски часто обоснованы скоростью разработки и поддержки приложений.
А если конструкция написана логично, то существует большая вероятность, что она будет так же логична и для компьютера.
П.С.
И кстати, преобразовывать красивый и логичный яваскрипт в быстрые команды должен браузер.
> А если конструкция написана логично, то существует большая вероятность, что она будет так же логична и для компьютера.

это наврятли

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

я изложил аналогичную мысль тремя листами выше ;-)
Понимание логичности программы с точки зрения процессора — это немаловажный навык программиста)
Напротив, абсолютно лишний навык. Должен быть хороший инструмент (язык + компилятор), который решал бы эту задачу за программиста. Иначе программист становится придатком компилятора, а это неправильно.

Зная архитектуру и логику работы для Intel x86, что делать при портировании на ARM? Переписывать?
Я имел ввиду не логику конкретного процессора, а общую логику. То есть, необходимо на нормальном уровне знать теорию алгоритмов. Например, чтобы не использовать пузырьковую сортировку 10 тысяч элементов в цикле.
в этом плане — да, программист должен уметь различать O(1) и O(n) и, как минимум, уметь пребразовать O(n*n) в O(2n) :)
Ну дык тут такая ситуация. Большинство проблем у яваскрипт и пхп тоже не от того, что языки плохие. Просто многие люди не отличают и этого, а также не тратят свои пару часов драгоценного времени, чтобы почитать стандарт.
эмм… неудачный пример, имхо.

У яваскрипта вообще проблем нет, есть только пожелание добавить в него лисповые макросы.

а вот пхп… как язык программирования, пхп должно умереть… ну или трансформироваться в JS, как наиболее близкий по синтаксису :)
Пхп долго будет умирать) Каким бы он косым и кривым не был, он работает, в нем есть удобный набор функций(пусть и с кривыми названиями), конструкций языка, справка и самое главное — отличная инфраструктура.
Абсолютно лишний? Теперь понятно откуда береца куча идиотов, которые даже не знают как цикл for работает, ибо они наверное также считают, что это абсолютно лишний навык.
> Теперь понятно откуда береца куча идиотов, которые даже не знают как цикл for работает

Вы действительно хотите поговорить об этом? Скажите, какая функция будет работать эффективнее:

function trim2 (string) {
var l = function (string) {
var i = 0;
for(z = string.length; string.charAt(i) == " " && i < z; i++);
return i;
};
var r = function (string) {
var i;
for(i = string.length; string.charAt(i) == " " && i >= 0; i--);
return i;
};
return string.substring(l(string), r(string));
};

var trim1 = function (str) {
for (var z = str.length, l = 0, r = z-1; ((str.charAt(l) == " ") && l++ < z) || ((str.charAt(r-1) == " ") && r-- > 0); );
return str.substring(l,r);
};
JS — язык удивительно гибкий, предоставляющий средства для решения множества типов задач. причем, гибкий настолько, что в его названии присутствует слово «script» (сценарий), а мы рассуждаем об инкапсуляции.

конечно, СНЯПом его именуют благодаря ярко выраженной специфике (утиная типизация, нативное прототипирование) и области применения. onclick'и, location.href и CSS-всегда-под-рукой никак не способствуют «каноническим» решениям повседневных задач — но позволяют добиться того, чего надо в кратчайшие сроки. и все бы хорошо, но…

… никто не хочет вызубрить работу с DOM'ом и всю жизнь только «дивы двигать». мы хотим более разнообразные задачи и более внушительным оклад. ООП! Оно и мозги расшевелит, и в технологи переведет.

Но и тут нам мало. Мы не хотим понимать, что такое ООП, мы хотим послушать, что о нем говорят наши коллеги и, сделав свои выводы, употреблять это слово в статьях, в резюме, в общении.

Года полтора назад я твердо заявлял: «Я знаю ООП!» Потому что я пользовался объектами и оператором new. Кастомный скроллинг с ноля? не вопрос, 8 часов, а если попрет, то вдвое меньше. Создать slider с кучей настроек, удобным API и гибкой взаимодействующей версткой — да пару дней, вместе с документацией и кучей рабочих примеров. Если я делаю такие сложные вещи (мне тогда так казалось) так быстро, используя new и объекты, то, само собой, я знаю ООП.

А потом мне попался калькулятор один. Сам бы я его не осилил просто. Писал я его под диктовку проект менеджера с 15 годами опыта в C++. День на третий я понял, что ООП это следствие развития науки со стажем многократно превосходящим срок жизни clien-side и обогатившейся за счет множества людей, даже более продвинутых, чем ПМ с 15 годами опыта в C++. Что я знаю об ООП? Ничего. Могу ли я, не понимая сути предмета, делать свои выводы? Наврядли.

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

Специфика это то, что накладывается на основу.

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

После этого фразы типа «не поняв зачем нужна инкапсуляция, не стоит отвергать её из-за специфики», если они конечно обращены ко мне, потеряют всякий смысл.
к Вам тоже. перечитал, скажу следующее:

> я против использования для этого кривых, неполноценных способов…
извиняюсь за демагогию, но под этими способами подразумевается локальная переменная. соответственно, когда все методы и все свойства наружу торчат, это «полноценность?»

>… которые в любом случае не решают поставленную задачу на 100%
а в чем задача? скрипт написать? или системку, которая будет удобна в изучении, изменении и переписывании?

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

надо проводить грань скриптованием и ООП. в т.ч. инкапсуляция, имхо, как раз лежит на этой грани.
> Вы считаете, что единственный смысл инкапсуляции — скрыть значение переменной?
Нет, я так не считаю, и в общем-то именно поэтому данная статья и написана.
Возможность гарантированно запретить доступ к внутреннему свойству объекта напрямую — как раз основная цель эмулирования приватных свойств тем способом, недостатки которого я здесь расмматриваю.

Если же осознанно применять инкапсуляцию для уменьшения связи между объектами, то нет никакой нужды что-то скрывать принудительно — это все равно что запрещать себе использовать, например, буквы «n» и «p» в названиях функций, ради следования определенной концепции )
> Нет, я так не считаю
Вы не представляете, как сильно я хочу увидеть в боге Javascript на популярном сайте статью на эту тему. что я вижу?
«Также к плюсам можно отнести экономию на слове this»
«Разница в 100-200мс может показаться несущественной, однако»
«Объекты с приватными свойствами сложнее в отладке»
это доказательная база? хоть бы слово про архитектуру, про то, что не надо все методы наружу показывать.

> нет никакой нужды что-то скрывать принудительно
есть, качество кода. если объект может делать do1 и do2, то зачем любому другому объекту, которому только do1 и do2 нужны, иметь возможность смотреть doWith и вызвать validateWith?
*в блоге
ненавижу опечатки
> если объект может делать do1 и do2, то зачем любому другому объекту, которому только do1 и do2 нужны, иметь возможность смотреть doWith и вызвать validateWith

видимо мы друг друга не поймем.

Объекты — они не живые, и даже не ИИ, это просто области в памяти, созданные кусками кода. Если не хотите, чтобы какой-то объект вызывал validateWith другого объекта — так не вызывайте, просто не пишите это в коде (ну или договоритесь с коллегами, чтобы они так не писали). Это не так сложно (договориться), как может показаться.

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

не все задачи можно процедурами решить. ну как, я слышал, что любой алгоритм можно на for/if реализовать, но мы больше о практике. когда надо в поле слово «поиск» убирать при фокусе, да, ООП не сдалось, но мы грим про ООП (ойжесть), а в ООП есть много традиций, выработанных дядями не злыми, а умными. почему-то против наследования никто не высказывается, а его в JS тоже нету.

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

Насчет «не надо задумываться как они там работают» — это, имхо, скорее разрекламированный идеал, чем объективная реальность. Я когда класс ZipArchive хотел использовать, тоже думал, что задумываться не надо. Оказалось что надо, потому что скрипт тупо валился при создании архива из папки с кол-вом файлов больше тысячи. Выяснилось что это такая бага zlib, скудно описанная где-то в заросших мхом багрепортах.

А вы говорите — «не надо задумываться», «сокрытие реализации».
почему не сделали? Вы сами их в статье написали и, напомню, call/apply работают аналогично new, «инстанцируя» объект, а не просто вызывая функцию. учитывая то, что иное применение у них только одно — вызвать фукнцию с нужным this, у меня не остается никаких сомнений в том, что умные дяди сделали-таки возможность для сокрытия свойств.

ну да, «не надо задумываться как они там работают» это перебор. но, опять же, от реализации зависит. ZipArchive, мне кажется, не самая тривиальная штука (не разбирался).

а песня, все-равно, другая: приятнее работать с чистым, продуманным объектом.
Если под '«инстарцируя» объект' подразумевается создание объекта — но это не верно для call/apply: call/apply не «инстанциируют» объект. Они просто выполняют функцию в контексте указанного объекта. Т.е.

(function (x) { this.x = x; }).call({}, 5);

не является эквивалентом:

var o = new function (x) { this.x = x; }(5);

потому что new делает еще кое-что за нас:

var New = function (f) {
var o = {};
return function () { return (f.apply(o, arguments), o); };
}

var f = function (x) { this.x = x; };

alert(New(f)(5).x); // 5
Ой капец, ошибка на ошибке) Спать-спать.
инстанцируя, конечно же

имелась ввиду возможножсть сохранить уникальность локальный переменных при «наследовании»:
function Q() {
	var a = 5;
	this.change = function() { a = 10; }
	this.alert = function() { alert(a); };
}

function W() {
	Q.call(this);
}

w1 = new W();
w1.change();
w2 = new W();
w1.alert(); // 10
w2.alert(); // 5


> new делает еще кое-что за нас
имелось ввиду, что вместо (f.apply(o, arguments), o) можно было бы просто написать new o(x)?
имелось ввиду, что собственно new, занимается созданием нового объекта, прописывает ему корректный prototype, а функция-конструктор только инициализирует этот объект согласно коду в теле функции.
О чем вы написали-бы в подобной статье, ну или хотели бы видеть? Можно тезисами.
1. ООП это не только хеш-объекты и оператор new;
1.1. наследование — самый главный (?), но далеко не единственный способ структурирования;
1.2. (как-то так) максимальный размер метода — семь строк;
2. Объекты представляют собою упрощенное, идеализированное описание реальных сущностей предметной области. Если соответствующие модели адекватны решаемой задаче, то работать с ними оказывается намного удобнее, чем с низкоуровневым описанием всех возможных свойств и реакций объекта. просто с вики скопировал, у Бутча было более лаконичное высказывание, как до книжки доберусь, посмотрю;
3. работа с DOM'ом — это далеко не все, на что способен JS;
3.1. работа с DOM'ом должна быть между делом, а не самоцелью;
3.2. (не совсем корректно, однако) роль сервер-сайда в проекте не обязана быть подавляющей, она может сводиться к набору сервисов; но даже если сервер-сайд играет подавляющую роль, клиент-сайд не обязан представлять из себя набор onclick'ов;
4. в споре «много кода vs гибкость/понимабельность кода» не может быть однозначного решения в любых условиях;
5. хватит считать миллисекунды, которые утекают у пользователя ради удобства разработки.
1. JS объектно ориентирован по самые гланды — объекты, инкапсуляция в общем смысле непосредственно в этих объектах, в более прикладном смысле — так, как это показано в статье, полиморфизм и динамика, наследование сквозь делегирование… Оператор 'new' само собой мало презентабелен, хеш-объектов в JS нет, есть объекты.

1.1. Какой-то не очень интересный пункт.

1.2. Семь строк?

2. Определение как определение. Одно из многих.

3. Неужели это кому-то не ясно, чтобы об этом отдельно писать. Для ёжиков: DOM — только лишь часть мира JS.

3.1. Небольшой скрипт для работы с DOM (only) может сделать и DOM самоцелью.

3.2. Не понял.

4. Клиент-сайд в его нынешнем виде всё-таки диктует приоритет малого кода.

5. Обязательно!!! нужно считать миллисекунды, размеры и проч. Клиента стоит уважать, ему на удобство моей/вашей разработки… с высокой башни..., ему нужно быстро и прозрачно.

DOM — это вообще не часть мира JS. ;-)
Ага, он возник отнечаделать…
ну это смотря как посмотреть
моя мысль такова:

RoR — это часть мира Ruby, потому что RoR без Ruby — не RoR :)
Аналогично: Django => Python, ZF => PHP, Hibernate => Java.

Теперь вопрос: существует ли DOM без JS? а JS без DOM?
DOM есть у браузера, это результат парсинга text/html, хотя этим можно и принебречь

DOM => JS, вроде как, оно и есть?

но у меня мысль другая: JS, будь он в 10 раз быстрее и выйди к нему хоть десятая спека, был бы экзотическим языком, если бы на нем нельзя было делать выпадающие менюшки
так ведь, если копнуть историю, можно вспомнить три момента:
1. Сначала был Netscape со своим JS и не было никакого DOM. Потом пришел MS со своим IE и показал, что IE4 — это круто, потому что у нас есть Jscript + DHTML (вот они, менюшки). И понеслась: в Netscape — layers, в MS — DHTML, HTA и прочие прибамбасы. В какой лагерь бежать — на тот момент было совершенно очевидно.

А вот потом уже появляется DOM, который оказался никому не нужен, кроме джавистов, потому что к моменту, когда рекомендация W3C была прочитана, усвоена и были созданы имплементации DOM — Netscape уже склеил ласты, а MS чхать хотел на мнение W3C.

2. VBscript, ActivePerl с такой плюшкой как client side Perl :) то что Javascript выжил, а остальные нет — скажем так, закон природы: vbs — слишком ущербен, ActivePerl появился не в неудачное время (тупо опоздали).

3. Думайте, как хотите, но не привязан DOM к какому-либо языку! DOM — это абстракция, методичка. Почитайте тот же W3C, что ли :)
да я ж согласен, что не привязан (DOM есть у браузера, это результат парсинга text/html), просто крайне проблематично говорить о JS вне браузера
А… вот в чем дело.

JS давно уже вышел за рамки браузера. Some buzzwords: SSJS, CouchDB, WSO2, Helma, jslibs, nekovm, mod_v8, llv8call.
4+5 экономия и выглаженность это всегда хорошо, но фанатеть, имхо, даже по ним не стоит. лучше по принципу Парето, 20/80, ибо 20% прироста скорости за счет увеличения срока в 4 раза оправданы в редких случаях (таже анимация).

1. не хочу комментировать
1.1. очень даже интересный, а особенно его грамотное применение, на эту тему очень много очень занимательных книжек есть :)
1.2. разбиение функционала на простые, понятные операции. откуда число 7 я не помню, может и 7, но точно не 77.
2. только понимают его очень мало людей. судя по x+getX+setX очень-очень мало людей :(
3. посмотрите, сколько людей строят всю «архитектуру» JS с помощью $() в jQuery, это понятно 10%
3.1. яспень, если надо в поле слово «поиск» убирать при фокусе, ООП не сдалось
3.2. логика веб-приложения не обязана находиться целиком на сервере
4. диктует чем? видео-баннерами, мегабитным анлимом, монстрами вроде extJS?
5. хотя высказывание и несколько резкое, но я выше уже писал, habrahabr.ru/blogs/javascript/65680/#comment_1842426
1. «не хочу комментировать», потому что чушь? ;)

3. $() и проч. гадость используется т.к. им удобно, дело даже не в DOM-центричности, а в упрощённой оболочке, на чём бы она не базировалась (хотя на чём, как не на DOM-e ей стоять в отношении browser scripting).

4. Диктует бережным отношением к НЕИЗВЕСТНОМУ клиенту, мы не знаем его канал, его оборудование, его возможности, мы обязаны беречь его миллисекунды и трафик. И совершенно не имеет значение то, что сеть наполнена видеобаннерами, кинАми и проч…
1. потому что я воспринял этот пассаж как набор прикольных слов. если Вас не затруднит по-русски пересказать как все это расшифровывается, плиз, не поленитесь, может и пойму чего

3. стоять на логике, на моделе поведения.

4. до какой степени? когда страница весит 861 KB uncompressed ну какой смысл стараться ужать 10, да и 50, кило скрипта? если скрипт инициализируется 100ms, пусть даже 500ms — что в этом страшного? эта страница у меня и дома, и на работе грузилась в разы дольше.

конечно, я не призываю плевать на пользователей. их надо любять, но себя тоже надо любить. а еще любить надо людей, которым наши творения надо будет переделывать — это тоже наши пользователи, просто из другой категории.
А я вот к примеру считаю что я ничему не обязан моему среднестатистическому пользователю. Кроме адекватной работы приложения без всяческих багов, глюков и выпадений. Знаетели, насмотрелся на кучу оптимизаций, когда все работает быстро-быстро, а что бы добавить новую фишечку, нужно полисистемы переписать.
7 забавное число, а если у меня будет шесть строчек? Мне дописать что-то в функцию? А 8? Уже удалять что-то из нее? А если у меня целых пятнадцать строчек? А если я ради оптимизации распаковал некоторые действия которые выполняются в большом массиве — то мне эти действия запихивать в еще одну функцию (которая в данном конктексте уже критична к скорости обработки.).

Думаю речь шла все таки о том, что функции должны быть короткими, что бы умещатся на одном экране, и очень желательно что бы они находились на одном уровне абстракции кода.
речь о том, чтобы можно было быстро понять, что делает do1:
1. за счет краткости, а экран кода это совсем не мало
2. и не увлекаться бытовым ИИ, а делать вещи простыми, проще разобраться в 5 методах из 7 строк, чем в одном «умном» методе на 70 строк
3. умеренное использование упрощенных записей, т.к. в одну строчку можно и управлятор мира написать
1. Безусловно, однако можно поподробнее, о чем вам кажется нужно упомянуть, учитывая что мы в scope of Javascript.
1.1. Можете перечислить способы, т.к. я не совсем понял пункт.
1.2. Я бы не бык так категоричен — любые правила нужно применять с головой:) Очень кстати перекликается со вторым пунктом(методы должны описывать поведение сущностей полностью).
3.,3.1 Абсолютно согласен, я тоже не понимаю как можно в серьезных проектах использовать jQuery :)
3.2. Вот это интереснее :) Я работаю над небольшим проектом и паралельно приходится писать фреймворк. В нем какраз подавляющая роль у клиента, идея в том что серверсайд используется для бд/синхронизации, причем желательно чтоб бэкенд был тоже ЖС.
4. Голову всегда надо иметь на плечах, если кто-то этого не понимает, значит не время ему понимать.
5. Вот тут не согласен, — нужно искать компромис между удобством разработки и скоростью. В конце концов, просто применения определенного кодинг стайла может увеличить скорость (типа while-- или code.google.com/intl/uk-UA/speed/articles/optimizing-javascript.html)
1. структурные и порождающие шаблоны проектирования. оператор call :) с помощью которого можно добиваться private-поведения переменных; и это не будет особым извратом, поскольку, в отличие от (ручной) эммитации protected, call не требует лишних телодвижений от базового класса. классы могут находиться внутри других классов, это и к 1.1. относится.
1.1. перечислить наврядли, но паттерны как раз про это.
1.2. с головой, да, только, когда метод занимает три экрана, пора бы подумать о выведении части действий в другие методы, наверняка их можно обособить и потом реюзать. семь — число относительное, не помню где я его взял, но просто опираясь на него, тяжелее писать громоздкий, не структурированный код.
1.2.1. из любого правила есть исключения.
2. «методы должны описывать поведение сущностей» — просто и понятно, в отличие от моей копипасты, спасибо, запомню.
3.2. значит, у Вас уже есть, что написать :)
4. 90% кодеров, говоря «JS» — подразумевают: «jQuery». к сожалению, у них нет ни предпосылок, ни мотивации задумываться об этом.
5. скорость выполнения — это всегда хорошо, но, опять же, однозначного ответа быть не может.
Спасибо за комментарии:)

4. — Это неплохо, если задуматься, т.к. ваша стоимость как спеца повышается, года ч-з 2-3 будете клаент сайд архитектором, а джейКвери спецы будут продолжать менюшками двигать вверх и вниз:)
UFO just landed and posted this here
Javascript в нынешнем виде — мёртвый язык. Вряд ли он проживёт более нескольких лет, так что вкладываться в него смысла нет. Google Microsoft Firefox включают потихоньку python, пора понять и всем нам что время Javascript прошло.
Проблема в том, что в нынешнем виде, в реализации гугла(V8) Javascript гораздо быстрее чем питон.
Конечно, не сразу всё пойдёт, несколько лет понадобится. Зато куча поклонников у питона есть, наработки, сам гугль любит питон. Скорость — дело наживное.
Я правильно понял, Вы знаете глубоко и Javascript, и Python? Или… наоборот — оба поверхностно? ;)
Javascript — вполне неплохо, питон — очень поверхностно. Но прочитать описание языка и понять разницу между языком с классами и языком без классов могу. Попробуйте почитать — может быть и Вы сможете.
Т.е. Вы считаете, что язык без классов — не язык?
А Вы читать умеете, или только по клавиатуре стучать?
стучать я умею в башку, бубен и барабан. а комменты добавляю силой мысли. :-P
> Javascript — вполне неплохо, питон — очень поверхностно

Нет, подождите ;) Вы рассуждаете в утверждающем ключе. Как это возможно при знании языков не на глубоком уровне? Чтобы разговаривать на языке утверждения (касательно Javascript, я могу говорить так, да и о Python't тоже) надо знать достаточно глубоко и теорию и практику.

> Попробуйте почитать — может быть и Вы сможете

Спасибо, «оценил» ;)

Попробуйте найти принципиально категоричные отличия Python'a от JS. Если Вам это удастся, покажите, мне интересно.
Я говорю это основываясь на…?

По мне так живее всех живых и позиций не сдает.
Хотя технологии и развиваются очень быстро, но на данном этапе Javascript практически единственный язык который используется для скриптования веб-приложений на стороне клиента. Сейчас это огромное количество кода и библиотек. Поэтому назвать его «мертвым» — у меня ну никак язык не поворачивается.
Думаю на наш век JS'а еще хватит.
Ну не верю, что все браузеры одномоментно откажутся и перейдут, да фиг с ними с браузерами, что будет с огромной толпой разработчиков сайтов?
«Javascript в нынешнем виде» — прекрасный, изящный и гибкий язык. Жаль, что многие люди «я знаю ООП!!11» этого не понимают.
То-то сейчас javascript-библиотеки расплодились как поганки после дождя, «мёртвый язык», безусловно. Наоборот сейчас он на пике популярности. Вообще если не в теме лучше промолчать, чем смешить собой других.
Расплодившиеся подпорки как раз показывают наличие в языке недостатков, которыми нельзя пренебрегать.
А дураков мне не лень смешить, смейтесь!
Расплодившиеся подпорки как раз показывают наличие в языке недостатков, которыми нельзя пренебрегать.

Может, давайте посчитаем объем «подпорок» для c# (один .net как 1000 jquery), java и прочих «языков с недостатками»?

И вообще, приведите пример «языка без недостатка» в Вашем понимании, на котором можно решать практические задачи без каких-либо библиотек, а то мне кажется, Вы что-то знаете, чего не знает никто другой.
Библиотеки для Javascript (те, о которых можно говорить в данном случае) предназначены для придания JS свойств «настоящих» OOP языков, а не для выполнения сервисных функций. Например, jQuery — это большей частью сервисная библиотека дл работы с DOM, она нужна при любой реализации ООП и подпоркой не является. prototype — большей частью (по крайней мере до последнего времени) попытка добавить ООП и подпоркой является.

Java, C++, C#, Python — не требуют подпорок для ООП.
> jQuery — это большей частью сервисная библиотека дл работы с DOM, она нужна при любой реализации ООП

любой!? нужна или, может, сразу необходима?
нужна в смысле «может быть использована», а не «необходима».

PS
Плиз, холивара не по теме не надо.
да, извиняюсь, просто не люблю я резкие высказывания
Вот я выше о Вас и говорил.
Причем тут ООП и javascript? Для Вас что, программирование = ООП?

JS не требует подпорок для ООП, их требуют плохие JS-разроботчики, которые не понимают язык, на котором пишут.
> предназначены для придания JS свойств «настоящих» OOP языков
>… Python — не требуют подпорок для ООП

А Вы видели большую принципиальную разницу между ООП-моделью Python'a и Javascript? ;)
А в питоне есть наследование, а в JS нет. Разницы не заметно?
> А в питоне есть наследование, а в JS нет

А приведите пример, если не сложно, в чём принципиальная большая разница наследования в Python'e и JS?

> Разницы не заметно?

В том-то и дело, что разницы Вы практически не увидите вообще никакой (если, конечно, Вы знаете и JS и Python не поверхностно, а достаточно глубоко, чтобы рассуждать, какой язык «мертвый», а какой нет)

Да, и, наследование в JS, конечно же, есть ;)
в JS наследования нет. Это аксиома. Есть эмуляция несколькими способами, с разными особенностями, но наследования нет на уровне языка. Нет приватных переменных — их можно эмулировать, но это не свойство языка.

Предъявите мне наследование в Javascript, если оно есть.
> Предъявите мне наследование в Javascript, если оно есть

мне не нравится подобные позиции; с чего-то, вдруг, люди, что-то отрицающие, всегда считают (безосновательно ;)), что им должны кто-то что-то предоставить. Мы, естественно, поменяемся местами, и это Вы мне предоставите все факты и теорию, что наследования в JS нет, хорошо? ;)

Я лишь натолкну на путь, где можно почитать о JS, и, в частности, о наследовании в JS — стандарт ECMA-262-3.

> в JS наследования нет. Это аксиома.

Что-то имеете против, если я назову это полной чушью?
Не надо с ним спорить: товарищ явно не в теме. Pilat какбэ намекает, что в JS наследование декларируется явно через prototype (либо достигается копированием) и, поэтому, настоящим наследованием не считается, забывая при этом, что по сути RTTI == prototype.

P.S. с точки зрения кремня, ООП не существует, а существует только спагетти условных переходов | call, которые сбивают ему кэш и предсказатель переходов. ;-)
Нельзя представить факты существования того, чего нет — это простая логика. А вот контрпример представить можно, например Вы могли бы представить пару-тройку строк кода, демонстрирующих возможность наследования. Например, что-то, реализующее функционал питона «class child_class (parent_class1, parent class2...)»
Может быть, стоит поднять архивы того же хабра — наследование обсуждалось несколько раз, и каждый раз вывод был один — без специальных библиотек наследование реализовать не удаётся.
Ну блин. Как горох об стену.

Пример наследования в JS без специальных библиотек. Тынц: code.google.com/p/nulljs/wiki/HowtoInheritance
function Foo() {}
function Bar() {}
Bar.prototype = new Foo();
  
var foo = new Foo();
var bar = new Bar();
alert(foo instanceof Object) 
alert(foo instanceof Foo)
alert(foo instanceof Bar)
  
alert(bar instanceof Object) 
alert(bar instanceof Foo)
alert(bar instanceof Bar)	


Результаты:
true, true, false
true, true, true


Надеюсь что такое instanceof объяснять не надо?
А если я захочу вызвать из bar какой-то метод foo, как я это сделаю?
function Foo() {}
function Bar() {}

Foo.prototype.sayHello = function() {
    alert('hello');
}

Bar.prototype = new Foo();
  

var bar = new Bar();
bar.sayHello();	  
> А вот контрпример представить можно

alert(1..toString());
И еще:
jQuery — это большей частью сервисная библиотека дл работы с DOM, она нужна при любой реализации ООП
какое отношение к «реализации ООП» имеет jQuery?
Выскажу свое мнение. Javascript — клиентский язык, значит код на нем должен: 1) как можно быстрее работать 2) как можно меньше весить. Вот и все. В топку ваши извраты, пишите приватные перемнные с подчеркивания, единственный минус этого подхода — весь код будет в знаках подчеркивания, и тяжело его набирать на клавиатуре (так как кнопка далеко расплоложена).
+1 Абсолютно согласен. Реюзу ради реюза гореть в аду.
Sign up to leave a comment.

Articles