Javascript-форум (https://javascript.ru/forum/)
-   Общие вопросы Javascript (https://javascript.ru/forum/misc/)
-   -   Непонятная структура кода (новичковый вопрос) (https://javascript.ru/forum/misc/4071-neponyatnaya-struktura-koda-novichkovyjj-vopros.html)

LowCoder 19.06.2009 19:36

Непонятная структура кода (новичковый вопрос)
 
На данном сайте есть статья по drag n drop
http://javascript.ru/ui/draganddrop

в ней есть такая структура

var dragMaster = (function() {
    // private методы и свойства
    var dragObject
 
    function mouseDown(e) {
        клик на переносимом элементе: начать перенос
    }
 
    function mouseMove(e){
        if (dragObject) {
            отобразить перенос объекта
        }
    }
 
    function mouseUp(e){
        if (dragObject) {
            конец переноса
        }
    }
 
    // public методы и свойства    
    return {
        init: function() {
            // инициализовать контроллер
            document.onmousemove = mouseMove
            document.onmouseup = mouseUp
        },
 
        makeDraggable: function(element){
            // сделать элемент переносимым
            element.onmousedown = mouseDown
        }
    }
 
}())



мне соверешенно непонятно зачем нужны скобки в перед словом function

var dragMaster =     =>(<= вот эта скобка function() и вот эти
}()) в конце


почему нельзя было написать?
var dragMaster = function() {...код функции с вложенными функциями ...}


но так не работает понятное дело :( Объясните плиз а то вообще не въеду. Только если можно подробно на уровне 1 класс 1 четверть. Статьи с сайта читал есть подозрения что надо курить замыкания. Но просто не понимаю что вообще это за конструкция

var somthing = ()


и не функция вроде и не объект.. Объект же объявляется через фигурные скобки... Совсем не пойму

Riim 20.06.2009 03:38

Функция создается и сразу запускается.

UDN 20.06.2009 05:37

Объясню на примере:
var ms=(new Date).getTime(); /*получить ms с 1970 года*/
Здесь скобки требуются для инициализации объекта
в противном случае потребуетсяв к функции обращатся так
var ms=(new Date);ms.getTime();
Подобная конструкция применяется для минимизации.
var start=(new Date).getTime();
... my code ...
var ms=(new Date).getTime()-start; на выходе скорость выполнения
участка кода.

UDN 20.06.2009 05:39

Проще говоря это одна из форм записи

UDN 20.06.2009 05:42

var dragMaster = function() {...код функции с вложенными функциями ...}
можешь записать
function dragMaster() {...код функции с вложенными функциями ...}

LowCoder 20.06.2009 06:30

Спасибо за ответы

LowCoder 20.06.2009 07:54

Цитата:

Сообщение от UDN (Сообщение 22483)
Объясню на примере:
var ms=(new Date).getTime(); /*получить ms с 1970 года*/
Здесь скобки требуются для инициализации объекта
в противном случае потребуетсяв к функции обращатся так
var ms=(new Date);ms.getTime();
участка кода.

Все равно есть непонятки
вот эти два примера кода выдают разный результат
var ms=(new Date).getTime();
alert("Time"+ms);

Time1245469872876
а этот
var ms=(new Date);
ms.getTime();
alert("Time"+ms);

выдает
TimeSat Jun 20 2009 07:50:16 GMT+0400

Т.е понятно что в первом случае это кол-во миллисекунд а второе тоже самое но в отформатированном варианте. Но как то неаккуратненько. (c) Т.е нельзя сказать что вызовы абсолютно идентичны. :-?

LowCoder 20.06.2009 08:18

И еще сорри за занудство - но даже ести это как бы создание функции и сразу её запуск то зачем нужны скобки в конце кода
}()) в конце блока кода


что они дают и зачем нужны? Без них кстати не работает. Почему нельзя было написать так
}var dragMaster = (function() {...} )


А занудство тоже оправдано поскольку этап первоначльного въезжание в язык наиболее сложный так как непонятны многие базовые концепции, а еще в такой язык как с ЖаваСкрипт с исключительно путанным синатксисом. Похоже разработчки стандарта ЕСМА употребляли .. причем даже не траву а что то сильно потяжелее. Совершенно непонятно зачем было делать настолько сложный и запутанный язык для совершенно прикладных задач. Но это конечно имхо.

Riim 20.06.2009 11:54

Цитата:

Сообщение от LowCoder
вот эти два примера кода выдают разный результат

Они и должны выдавать разный результат.

Цитата:

Сообщение от LowCoder
но даже ести это как бы создание функции и сразу её запуск

Ни если даже, а так и есть.

Цитата:

Сообщение от LowCoder
что они дают и зачем нужны? Без них кстати не работает.

Они запускают эту созданную функцию.

Цитата:

Сообщение от LowCoder
с исключительно путанным синатксисом

Цитата:

Сообщение от LowCoder
Совершенно непонятно зачем было делать настолько сложный и запутанный язык

Мне все это сразу понятно становилось. Не знаю, что вы тут путанного увидели.

Dmitry A. Soshnikov 20.06.2009 13:35

LowCoder,

Материал:

- "проблема": http://javascript.ru/ecma/part12#a-12.4
- решение: http://javascript.ru/ecma/part11#a-11.1.6

Скажу кратко (подробно, нужно потратить больше времени, текста и уже нужно иметь определённую теоретическую базу), чтобы не путать.

Функции деляться на:

- "Функция-Объявление" (FunctionDeclaration, FD);
- "Функция-Выражение" (FunctionExpression, FE).

Разницу сейчас тоже не буду описывать, т.к. это не важно в данном вопросе.

Так вот, исходя из п.12.4:

Цитата:

ИнструкцияВыражение не может начаться с открывающей фигурной скобки, т.к. тогда оно было бы неотличимо от Блока. Также ИнструкцияВыражение не может начинаться с ключевого слова function, т.к. тогда оно было бы неотличимо от ОбъявленияФункции
Т.е.

function a() {}();


Ошибка, т.к. неотличимо от "Функция-Объявление", которую нельзя вызвать сразу.

Соответственно, нужно переделать выражение так, чтобы оно стало "Функция-Выражение". Самый простой способ - оператор группировки.

(function a() {})();


Все ок, т.к. теперь это FE.

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

var a = (function () { var b = 10; return b; })();


Создаём FE, и тут же её вызываем. Переменная "а" теперь 10, но переменная "b" не существует после вызова функции.

Конструкию (function () { _наш_код_ })(); можно назвать инициализирующим пространством нашего объекта/библиотеки и т.д. Это пространство позволит вернуть наружу минимальный интерфейс, но (повторюсь) внутри себя иметь множество дополнительных, вспомогательных объектов, которые будут не видны снаружи:

var a = (function () {
  
  // "private"
  var b = 10;
  
  function c() {
    return b + 10;
  }

  // интерфейс наружу
  return {
    test: c,
    q: b,
    z: function () {
      return c() + 10;
    }
  };  

})();

// "a" инициализирован
// надеюсь, понятно, что "а" - есть возвращённый объект, но не функция!
// функция (FE) использовалась нами лишь для создания
// "нашего пространства" и для возвращения этого объекта

alert(a.test()); // 20
alert(a.q); // 10
alert(a.z()); // 30


Однако, ни "b", ни "c" не доступны посредством "а" напрямую.

Riim 20.06.2009 16:57

Цитата:

Сообщение от Dmitry A. Soshnikov
(function a() {})();

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

(function a() {}());

Dmitry A. Soshnikov 20.06.2009 17:28

Цитата:

Сообщение от Riim
(function a() {})();
(function a() {}());

Обе конструкции - правильные FE, и будут работать.

LowCoder 20.06.2009 17:46

Большое спасибо, осбоенно Dmitry A. Soshnikov за ответы. Очень подробне и обстоятельные. Буду разбиратся дальше. Я писал много на С++ но JavaScript мне кажется "диким" :) языком после С++. Видимо я не могу пока понять практического смысла столь сложных конструкций. Буду разбиратся. Еще раз сапсибо.

Riim 20.06.2009 20:14

Цитата:

Сообщение от Dmitry A. Soshnikov
Обе конструкции - правильные FE, и будут работать.

Почему первый вариант правильный мне ясно: сначала написано "function a() {}", т. е. FD который не может сразу запускаться, он записан в скобки, про которые написано:
Цитата:


вычисляется по следующей схеме:

1. Вернуть (normal, empty, empty).

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

Цитата:

Сообщение от LowCoder
Я писал много на С++ но JavaScript мне кажется "диким" языком после С++.

Часто такое слышу, но в основном проблемы из-за прототипирования вместо стандартного ООП, т. е. основные проблемы у вас еще впереди.

Dmitry A. Soshnikov 20.06.2009 20:50

Riim, в любом случае - в скобках - (...) - может быть только FE.

Цитата:

Сообщение от LowCoder
JavaScript мне кажется "диким" языком

собственно, ровно то же самое, можно было сделать обычной FD:

function initDragMaster() {
    // private методы и свойства
    var dragObject
 
    function mouseDown(e) {
        клик на переносимом элементе: начать перенос
    }
 
    function mouseMove(e){
        if (dragObject) {
            отобразить перенос объекта
        }
    }
 
    function mouseUp(e){
        if (dragObject) {
            конец переноса
        }
    }
 
    // public методы и свойства    
    return {
        init: function() {
            // инициализовать контроллер
            document.onmousemove = mouseMove
            document.onmouseup = mouseUp
        },
 
        makeDraggable: function(element){
            // сделать элемент переносимым
            element.onmousedown = mouseDown
        }
    }
 
}

var dragMaster = initDragMaster();


Здесь есть основной минус - функция initDragMaster остаётся жить в глобальном пространстве, даже, когда она уже не нужна. Поэтому, обычно, для создания инициализующего скопа, и создают (анонимную) FE, которая выполнится сразу после создания и уничтожится (тем не менее, весь её внутренний контекст будет доступен в возвращённом объекте; но это уже тема про замыкания).

Цитата:

Сообщение от Riim
но в основном проблемы из-за прототипирования вместо стандартного ООП, т. е. основные проблемы у вас еще впереди.

Да ладно, не пугайте заранее ;) Ничего там сложного нет. Не устану повторять, что разница "Класс" vs. "Прототип" не столь существенна, как "Статика" vs. "Динамика". Ну да, в случае с С++, будет казаться нечто странным поначалу. А, например, тем, кто пришел в JS из Python - что прототипы, что классы - особой разницы не заметят, т.к. Pyhton тоже полностью динамичный.

LowCoder 20.06.2009 22:25

Ну да - JavaScript кажется мне именно странным. Это очень точный термин. Из за очень большой свободы JavaScript кажется мне очень трудночитаемым языком в плане синтаксиса. Когда я первый раз увидел вложенные функции, обращения к переменным до их объявления, констрекции типа
var v= function() ...

, добавление свойств и методов "по ходу дела" ну и еще ряд мелочей у меня волосы встали дыбом :)
Надо конечно все это еще исследовать сильно. Я просто не понимаю зачем для веб програмирования, которое является чисто прикладной задачей был выбран такой сложный стандарт. Также и для АкшнСкрипт. Сделал на нем небольшой проект с нуля - измучился совершенно. По идее для таких задач должны были использоватся очень простые языки, что бы любой офисный работник мог бы освоить скажем типа ВизуалБейсик. Там все прямолинейно, логично, быстро и относительно безглючно. А тонкие ньюансы и навороченные фишки приводят имхо к сильнопутанному синтаксису и соответственно глюкам и трудноуловимым багам. Впрочем это мои первые и чисто субъективные впечатления.

Riim 21.06.2009 09:55

Цитата:

Сообщение от Dmitry A. Soshnikov
в любом случае - в скобках - (...) - может быть только FE.

В общем-то, объяснение: "так положено и все тут" меня вполне устраивает. Да и все мои эксперименты говорят, что это действительно так. Причем даже подсветка синтаксиса в Visual Studio 2008, похоже, в курсе всей этой темы.

Dmitry A. Soshnikov 21.06.2009 11:43

Цитата:

Сообщение от Riim
объяснение: "так положено и все тут" меня вполне устраивает

Да что Вы? ;)

http://javascript.ru/ecma/part11#a-11.1.6

В скобках - уже expression. Всегда expression. Касательно функции, - FE.

Riim 21.06.2009 13:53

Цитата:

Сообщение от Dmitry A. Soshnikov
В скобках - уже expression. Всегда expression. Касательно функции, - FE.

То, что так задумано мне ясно, не ясно зачем.

Dmitry A. Soshnikov 21.06.2009 18:13

Цитата:

Сообщение от Riim
То, что так задумано мне ясно, не ясно зачем.

Что не ясно "зачем"? Почему, оператор группировки всегда внутри себя содержит выражение? Грамматика такая. А что ещё, по Вашему, он там может содержать?

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

var a = {
  b: function () {
    return 10;
  }()
};

alert(a.b); // 10


Почему? Потому что парсер уже распознал функцию как FE. В случае же описания в начале темы - есть неоднозначность - путаница с FD, поэтому парсер выдаёт ошибку. Когда же мы помещаем её в оператор группировки, внутренности которого всегда являются expression'ом (а что ещё, по Вашему, там может быть? ;)), парсер однозначно определят функцию, как FE, и выполняет.

Riim 21.06.2009 18:44

Цитата:

Сообщение от Dmitry A. Soshnikov
её в оператор группировки, внутренности которого всегда являются expression'ом (а что ещё, по Вашему, там может быть?)

Что-то я об этом не подумал. Действительно, оператор группировки задуман для "выделения" частей !выражения! , а значит, его содержимое и не должно восприниматься по-другому. В таком случае с FE все вполне логично, а FD что за зверь?

Dmitry A. Soshnikov 21.06.2009 18:55

Цитата:

Сообщение от Riim
а FD что за зверь?

Вот здесь немного есть; если нужно будет подробней и глубже, зовите.

Define 05.05.2014 19:04

(function(a,b){..код..})(a,b)

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

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


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