Javascript-форум (https://javascript.ru/forum/)
-   Общие вопросы Javascript (https://javascript.ru/forum/misc/)
-   -   Одиночки. В чем разница? (https://javascript.ru/forum/misc/1268-odinochki-v-chem-raznica.html)

Snipe 02.06.2008 11:58

Одиночки. В чем разница?
 
Одиночки.
Есть ли разница и если есть, то в чем она заключается?
Раз:
var NewObject = {};
(function() {
  var privateStr = 'Я приватная';
  NewObject = {
    methodX: function() {
      alert(privateStr);
    }
  }
})
NewObject.methodX();

Два:
var NewObject = new function() {
  var privateStr = 'Я приватная';
  this.methodX = function() {
    alert(privateStr);
  }
}
NewObject.methodX();

tenshi 02.06.2008 12:18

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

Snipe 02.06.2008 12:23

Цитата:

Сообщение от tenshi
второй код короче.
но оба бестолковы.. не стоит использовать замыкания для сокрытия состояния объекта. от этого больше неудобств, чем пользы.

А как тогда прятать не нужные мне в глобальной области видимости элементы?

Kolyaj 02.06.2008 13:11

Цитата:

Сообщение от Snipe
А как тогда прятать не нужные мне в глобальной области видимости элементы?

Они и не будут в глобальной области, они будут свойствами соответствующего объекта.

Snipe 02.06.2008 13:24

Цитата:

Сообщение от Kolyaj (Сообщение 2750)
Они и не будут в глобальной области, они будут свойствами соответствующего объекта.

Это понятно, но я же их не использую вне объекта. Т.е. в принципе мне не надо NewObject.privateStr, даже наоборот, хочу сделать privateStr недоступным.

Kolyaj 02.06.2008 13:45

Цитата:

Сообщение от Snipe
хочу сделать privateStr недоступным.

А в результате страдает читабельность кода, скорость скрипта, количество используемой памяти. Оно надо?

Snipe 02.06.2008 14:00

Цитата:

Сообщение от Kolyaj (Сообщение 2752)
А в результате страдает читабельность кода, скорость скрипта, количество используемой памяти. Оно надо?

Конечно же необязательно. :)
Просто захотелось.

Кстати, а где тогда можно уточнить про влияние таких вот изворотов на скорость скрипта?

hogart 02.06.2008 15:48

Snipe, экспериментируйте:)

Но мысль на самом деле правильная. В большом проекте лучше скрывать ненужное. Инкапсуляция в ООП для этого и придумана.

Dmitry A. Soshnikov 02.06.2008 16:48

Snipe, посмотрите разницу для обоих случаев в:

alert(NewObject.constructor); // => NewObject.[[prototype]].constructor


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

vasa_c 02.06.2008 17:47

Замыкания внутри конструкторов создают скорее не приватные свойства объектов, а приватные статические переменные "классов".И в этой ипостаси, они очень удобны. А городить всё это ради одного свойства, скорее всего, не стоит

Snipe 02.06.2008 17:54

Цитата:

Сообщение от vasa_c
А городить всё это ради одного свойства, скорее всего, не стоит

Никто не говорил что оно одно, это просто пример. Или мы о разном?

vasa_c 02.06.2008 18:05

В этом примере не стоит. Если вы приведете другой, тогда можно о нём и поговорить.

Snipe 02.06.2008 18:31

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

На счет стоит-не стоит - пока ни единого разры... тьфу обоснования кроме личных предрасположенностей не встретил.
Мне так нравится писать, на мой вгляд если функция не нужна вне, то во вне её быть не должно.
Читаемость кода от этого не страдает совсем. Даже наоборот!

Есть реальная разница в скорости? Ну или хотябы возможность это проверить?

Цитата:

Сообщение от Dmitry A. Soshnikov
Поэтому, если говорить об инициализирующем скопе, то первый вариант подойдет больше, т.к. во втором случае получается инстанс анонимной функции.

Извиняюсь, не совсем понял, во втором случае у нас еще остается анонимная функция, которой в первом случае нет?
Получается во втором случае инфа хранится дважды?

tenshi 02.06.2008 18:58

есть замечательный скрипт для дампа объекта в целях отладки:

function dump( obj ){
    var pairs= [];
    var blocked= [];
    if( obj ) for( var key in obj ){
        try{ 
            pairs.push( key + ': ' + obj[ key ] );
        } catch( e ){
            blocked.push( key );
        }
    }
    if( pairs ) obj+= ' {', pairs.join(', '), '}';
    if( blocked ) obj+= '[blocked: ' + blocked.join(', ') + ' ]';
    return obj;
}


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

vasa_c 02.06.2008 19:13

>Естественно, что они используются, когда возникает возможность совпадения имен
Совпадение имён здесь совершенно никаким боком.

>Есть реальная разница в скорости? Ну или хотябы возможность это проверить?
Да. Описать эту возможность?

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

Андрей Параничев 02.06.2008 19:29

Я тоже считаю, что если в JavaScript нету встроенного разделения на private/public, то изворачиваться через закрытие области видимости - кощунство.

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

Dmitry A. Soshnikov 02.06.2008 21:29

> Извиняюсь, не совсем понял, во втором случае у нас еще остается анонимная функция,

Да.

Еще раз: первый подход вполне уместен (и именно для обеспечения того, чтобы не засорять глобальный объект), когда речь идет об инициализации, и внутри этой инициализации используются вспомогательные локальные var'ы.

Скоп этой "singleton'ной" функции будет доступен внутренним замыканиям и, как следствие, свойствам иницализируемого объекта. Но в отличии от второго случая, функция не будет жить дальше (во втором - будет - и зачем это надо? Поэтому первый способ - предпочтительней).

Цитата:

Сообщение от vasa_c
>Есть реальная разница в скорости? Ну или хотябы возможность это проверить?
Да. Описать эту возможность?

А о каких скоростях идет речь? Первого и второго подходов? А что за возможность? =)

Андрей Параничев 02.06.2008 21:42

А где в примере из первого поста singleton? В моём преставлении этот паттерн реализуется в виде метода, возвращающего ссылку на экземпляр класса. Или я не прав? Хотя зачем такое в JavaScript, тут вообще классов по сути нету.

tenshi 02.06.2008 22:18

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

Dmitry A. Soshnikov 02.06.2008 22:25

Цитата:

Сообщение от Андрей Параничев
Или я не прав?

Прав =) Более того, даже и второй случай синглтоном (в понимании паттерна при классовом ООП) нельзя считать (в том плане, что даже и нет возможности повторно обратиться к "классу", чтобы он вернул тот же инстанс). Просто данную конструкцию - (function() { ... __init__(); ... })(); - иногда называют (инициализирующим) синглтоном. И в ключе использования вспомогательных инициализирующих var'ов и локальных функций (именно для этого и выделяется локальный скоп этой анонимной функции, которая запустится единожды и исчезнет (если, конечно, не будет ссылок на нее), хотя, скоп ее останется)) - вполне удобно.

Скорость определения замкнутых var'ов, естественно, будет медленнее, т.к. они находятся не в родном скопе (в смысле, return this.a будет быстрее, чем return a, где a - локальный замкнутый var).

А подобие (имитация) классического паттерна могла бы выглядеть, например, так:

function SingletonClass() {
}

SingletonClass.getInstance = function() {
  if (!SingletonClass.instance) {
    SingletonClass.instance = new function() {
      this.a = 10;
      return true;
    };
    SingletonClass.instance.getA = function() {
      return this.a;
    };
    SingletonClass.instance.setA = function(a) {
      this.a = a;
      return true;
    };
  }
  return SingletonClass.instance;
};

var a = SingletonClass.getInstance();
a.setA(20);
var b = SingletonClass.getInstance();
alert(b.getA());

Snipe 03.06.2008 00:28

Цитата:

Сообщение от tenshi
сокрытие переменных приводит к тому, что мы не можем полноценно отлаживать приложение, ибо не можем получить полное состояние объекта

Если честно ни разу не приходилось отлаживать приложения.

Цитата:

Сообщение от vasa_c
Да. Описать эту возможность?

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

Цитата:

Сообщение от vasa_c
Обоснования были даны совершенно чёткие - страдает читабельность кода, скорость скрипта, количество используемой памяти.
Замыкания позволяют создать аналог скрытых свойств и перенос напрямую всех подходов из "классового" ООП обычно не приводят ни к чему хорошему.

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

По поводу читаемости и эстетики, если у вас используется несколько JS файлов, отдельно для комментариев, отдельно для меню и пр., можете поверить на слово, без инкапсуляции код будет читаться гораздо сложнее чем с (можете, правда, и не поверить). Вполне допускаю, что будет несколько функций с одинаковыми именами. И чем больше проект, тем сложнее будет слдеить за отсутствием повторов. А если использовать библиотеки со стороны, у которых тоже все функции вывалены прям так...
Так что предлагаю тему читаемоости закрыть сразу и больше к ней не возвращаться. Делали - читаемо. :)

Цитата:

Сообщение от tenshi
такой подход не может быть уместен, ибо все методы создаются заново при каждом инстанцировании объекта.

На какой пост ответ? :confused:

Вот это я понимаю тема, интересно обсудить, а то все "как сделать, чтоб onclick работал?" :)

Продолжаем разговор.

Dmitry A. Soshnikov 03.06.2008 01:13

Цитата:

Сообщение от Snipe
Я имел ввиду, что никто не сказал "у меня есть опыт" или "я провел эксперимент и точно знаю, вот цифры".

"У меня есть опыт и я провел эксперимент и точно знаю" то, о чем написал Вам уже два раза. =)

Snipe 03.06.2008 01:28

Цитата:

Сообщение от Dmitry A. Soshnikov (Сообщение 2790)
"У меня есть опыт и я провел эксперимент и точно знаю" то, о чем написал Вам уже два раза. =)

О, это не к вам обращение. Вам как раз спасибо за объяснения! Была бы тут карма, поднял бы )))

Андрей Параничев 03.06.2008 01:44

Snipe,
По моему личному опыту, самый читабельный ОО код (в JavaScript) - когда весь объект представлен одним хэшем. Хотя из-за проблемы с запятыми, такой вид не очень удобен.

Snipe 04.06.2008 07:30

Раз:
http://habrahabr.ru/blog/webdev/43781.html
Два:
http://habrahabr.ru/blog/webdev/43805.html

tenshi 04.06.2008 12:24

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

конфликты имён решаются элементарно посредством неймспейсов.

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

hogart 04.06.2008 13:27

tenshi, не знаю, у меня используются замыкания для сокрытия и число отступов очень мало где превышает 3.

Читаемость -- тема отдельной беседы. Кто-то например может ставить фигурные скобки в микрософтовском стиле, а лично мне такой код нечитабелен.

tenshi 04.06.2008 22:19

это пока у тебя скрипты маленькие...

hogart 05.06.2008 11:04

tenshi, конечно, маленькие -- каждый обьект в своем файле.

Kolyaj 05.06.2008 13:08

Цитата:

Сообщение от hogart
у меня используются замыкания для сокрытия

Т.е., если объект имеет 10 методов и создается 10 объектов, браузеру приходится создавать 100 функций вместо 10 возможных.

Читабельность, конечно, вопрос индивидуальный, но мне комфортней
var f = function() {};
f.prototype = {
  m1: function() {},
  m2: function() {},
  m3: function() {}
};
чем
var f = function() {
  this.m1 = function() {};
  this.m2 = function() {};
  this.m3 = function() {};
}

hogart 05.06.2008 13:15

Kolyaj, а если обьект библиотечный и создается в одном экземпляре? Конечно, в контролах замыкания лучше не использовать.

Kolyaj 05.06.2008 13:20

Цитата:

Сообщение от hogart
а если обьект библиотечный и создается в одном экземпляре?

var Singleton = {
  init: function() {},
  m1: function() {},
  m2: function() {}
};
Singleton.init();

Тут я вообще не вижа смысла городить конструкцию вида
var Singleton = new (function() {
  ...
})()
ибо лишняя цепочка прототипов

hogart 05.06.2008 16:16

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

tenshi 05.06.2008 20:42

hogart, что, и вложенных объектов нет?

hogart 05.06.2008 21:15

tenshi, стараемся не делать.

tenshi 06.06.2008 09:13

ага! стараемся, но всё-таки бывают?

hogart 06.06.2008 10:04

tenshi, я поищу сегодня, если будет время. Навскидку не помню. Но JS к проекту писало как минимум три человека, там всякое бывает:)
Как минимум есть анонимные хэши, предназначенные для передачи параметров. Это считово?:)

tenshi 06.06.2008 11:36

всё считается, что порождает отступы :-)

hogart 06.06.2008 13:29

tenshi, ну, хэш с параметрами обычно пишется как-нить так:
{userid: this.userid, name: this.name}

Обходимся без отступов:)

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

Kolyaj 06.06.2008 13:54

Цитата:

Сообщение от hogart
кои файлики подгружаются по надобности

Подключение 40+ js-файлов на одну страницу, это как чересчур тормознуто. Я на страницу "Записать мысль" заходить боюсь.


Часовой пояс GMT +3, время: 14:36.