[identity profile] alia-the-pony.livejournal.com posting in [community profile] useful_faq
Пытаюсь допилить код MP3-плеера для сайта, написанного на JS. Он начинается со строки:

var playerExEngine = new playerFlash(function() {


Немного упростим задачу. Я написал функцию внутри объекта:

var playerExEngine = new playerFlash(function() {
     function i_hate_javascript () {
          alert('JavaScript sucks!');
     }
});


Как мне вызвать эту функцию извне? playerExEngine.i_hate_javascript() не работает, просто i_hate_javascript(), разумеется, тоже. Чего я только не перепробовал, не работает и всё тут. =(

Date: 2014-02-01 06:55 pm (UTC)
From: [identity profile] okosama-starr.livejournal.com
playerExEngine.i_hate_javascript() и не будет работать же
это дурацкие яваскриптовые замыкания
вообще, я бы вывел нужную функцию в виде функции вовне, и с ней бы работал.

Date: 2014-02-01 07:21 pm (UTC)
From: [identity profile] dendrr.livejournal.com
Давненько я не брал в руки Джаву, могу и напутать с другими языками... Но тем не менее.
(а трекинг-то что показывает, кстати?)

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

И согласен с предыдущим оратором - в чем проблема определить функцию "снаружи"?

Date: 2014-02-01 09:07 pm (UTC)
From: [identity profile] dims12.livejournal.com
А какой Ваш основной язык?

JavaScript не sucks. Там функция -- это тоже объект и от отличается от обычных объектов, которые с полями и методами. Похоже на Runnable из Java. Он создаётся в тот момент, когда исполняется код, содержащий определение функции. Само тело функции не исполняется до тех пор, пока Вы его не вызовете.

Например, в Джава

new Runnable() {
   public void run() {
      new Runnable() {
          public void run() {
              System.out.println("I hate world");
          }
      }
   }
}


метод run() не вызовется, он просто создастся.

В момент создания функции, происходит замыкание (closure) то есть, функция "фотографирует" все переменные, которые существовали в момент её создания. В Javascript замыкание полноценное, а Java потребует от Вас сделать переменные final (то есть, Java не умеет полноценно "фотографировать").

По Вашему коду.

Что делает конструктор playerFlash (я не в курсе)? Вы ему передали безымянную функцию. Внутри этой безымянной функции есть код, который создаёт функцию с именем i_hate_javascript.

Если конструктор playerFlash не исполняет безымянную функцию, которую Вы ему передаёте, то достучаться до функции i_hate_javascript нельзя, ибо она ещё не создана.

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

Если исключить неизвестный мне конструктор и написать вот так

function f1() {
   return function f2() {
      return function f3() {
         alert('I hate world');
      }
   }
}


то есть, сделать, чтобы каждая функция возвращала вложенную, то вызвать внутреннюю можно вот так

f1()()()

то есть, три вызова: вызвать f1, результатом будет f2, вызвать f2, результатом будет f3, вызвать её.

Скобки означают вызов.

Можно написать иначе

a1 = function () {
   a2 = function() {
      a3 = function() {
         alert('I hate world');
      }
   }
}


Тогда каждая функция будет создавать другую в момент вызова и класть её в свою переменную

Тогда, чтобы вызвать самую внутреннюю, надо сделать три вызова по очереди

a1(); // создалась функция a2 и её можно вызывать
a2(); // создалась функция a3 и её можно вызывать
a3(); // покажет алерт

Обратите внимание, что переменные не вложенные, они все "верхнего уровня".

Чтобы воссоздать множество вложенных объектов, нужно использовать слова this и new

b1 = new function() {
   this.b2 = new function() {
      this.b3 = function() {
         alert('I hate world');
      }
   }
}


Здесь new не использовано в последнем случае

new превращает функцию в конструктор объекта и выполняет её сразу. конструктор возвращает this, то есть, "содержимое" объекта с полями и методами (как в Java)

То есть, строчка b1= вызвала функцию-конструктор и положила её содержимое в b1

содержимое сконструировалось таким образом, что оно состоит из переменной b2, в которую положилось ещё вложенное содержимое, которое состоит из переменной b3. Внутри этой переменной лежит уже не object, а функция.

Чтобы её вызвать, надо написать так

b1.b2.b3();
Edited Date: 2014-02-01 09:09 pm (UTC)

Date: 2014-02-02 04:10 am (UTC)
From: [identity profile] gati.livejournal.com
вы просто забыли волшебное слово:

playerExEngine.пожалуйста.i_hate_javascript()

Date: 2014-02-02 10:54 am (UTC)
From: [identity profile] chapai67.livejournal.com
Это дичь конечно так писать.
.
Но есть два варианта
например

var playerFlash = function(){};
playerFlash.prototype.foo = function () {
alert("JavaScript sucks!");
}

var playerExEngine = new playerFlash;

тогда позвать просто playerExEngine.foo();


или

var playerExEngine = new playerFlash(function() {
//определяем явно и это плохо
playerExEngine.foo= function() {
alert("JavaScript sucks!");
}
});

playerExEngine.foo();

или более правильно (это должно срабоать если playerflash исполнит переданную ему как параметр функцию)

var playerExEngine = new playerFlash(function() {
this.foo = function () {
alert('JavaScript sucks!');
}
});


или можно повесить хэндлер на на событие - скажем кастом эвент.

Edited Date: 2014-02-02 11:29 am (UTC)

Date: 2014-02-02 01:15 pm (UTC)
From: [identity profile] chapai67.livejournal.com
ну по сути это хак - дырка вовнутрь коробки и веревочка. Честнее было бы сделать все же интерфейс..