• Najnowsze pytania
  • Bez odpowiedzi
  • Zadaj pytanie
  • Kategorie
  • Tagi
  • Zdobyte punkty
  • Ekipa ninja
  • IRC
  • FAQ
  • Regulamin
  • Książki warte uwagi

Wywołanie zagnieżdżonej funkcji z innej funkcji poprzez callback

VPS Starter Arubacloud
0 głosów
456 wizyt
pytanie zadane 10 stycznia 2016 w JavaScript przez ScriptyChris Mędrzec (190,190 p.)

Mam taką strukturę:

var obj = {
   first: function(callback)
   {
      /* some code */

      this.foo = function()  // chce wywolac foo() poprzez callback
      {
        /* some code*/
      };

      if (callback) callback();  
   },

   second: function()
   {  
     /* some code */

     var bar = function()
     {
        /*some code */
     };
     bar();

     obj.first(foo);  // chce wywolac foo(), gdy bar zakonczy swoje dzialanie
   }
}
obj.first(); // wywoluje first(), wiec foo() umieszczone w srodku jest juz utworzone, zanim go wywolam callbackiem
obj.second(); // wywoluje second(), w ktorym chce uzyc callbacka

Coś ze scopem pomieszałem, bo otrzymuje komunikat Uncaught ReferenceError: foo is not defined

Wiem, że obj.first.foo(); mogę umieścić na końcu bar(), ale chyba nie tu tkwi problem?

Czy da się wywołać funkcję foo()  w takim sposób?

1 odpowiedź

+1 głos
odpowiedź 10 stycznia 2016 przez Comandeer Guru (599,730 p.)
wybrane 12 stycznia 2016 przez ScriptyChris
 
Najlepsza

Tak na logikę, wywołujesz first w kontekście obj, więc this odnosi się do obj… Więc Twoja funkcja foo stała się metodą obiektu obj ;)

Inna rzecz: po co tak kombinować?

komentarz 10 stycznia 2016 przez ScriptyChris Mędrzec (190,190 p.)

Chcę wywołać foo() poprzez callback, bo chcę aby foo() uruchomiło się, gdy bar() zapełni pewien obiekt (czyli, zakończy swoje działanie), na rzecz którego foo() ma wykonać pewne rzeczy.

Potrzebne mi to, bo funkcja foo() musi zawierać się w scope funkcji first(), bo są tam dane potrzebne jej do działania.

Jeśli zamiast this, wstawię var foo = ..., to mam ten sam błąd.

Jak to zapisać prawidłowo?

[edit]

Potrzebne mi to, bo funkcja foo() musi zawierać się w scope funkcji first(), bo są tam dane potrzebne jej do działania.

Spróbowałem też wywołać foo() poprzez obj(foo); i ten sam błąd. 

komentarz 10 stycznia 2016 przez Comandeer Guru (599,730 p.)
A czemu po prostu nie wywołasz tej funkcji w kontekście odpowiedniego obiektu: https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Function/call
komentarz 11 stycznia 2016 przez ScriptyChris Mędrzec (190,190 p.)

Próbowałem i tym razem callback okazuje się być 'undefined' i funkcja nie wywołuje się.

komentarz 11 stycznia 2016 przez Comandeer Guru (599,730 p.)
				var obj = {
   first: function(callback)
   {
	  /* some code */
 
	  this.foo = function()  // chce wywolac foo() poprzez callback
	  {
		/* some code*/
	  };
 
	  if (callback) callback();  
   },
 
   second: function()
   {  
	 /* some code */
 
	 var bar = function()
	 {
		/*some code */
	 };
	 bar();
 
	 this.first(this.foo);  // chce wywolac foo(), gdy bar zakonczy swoje dzialanie
   }
}
obj.first(); // wywoluje first(), wiec foo() umieszczone w srodku jest juz utworzone, zanim go wywolam callbackiem
obj.second(); // wywoluje second(), w ktorym chce uzyc callbacka

Ale jak musisz konstruować takie rzeczy, to znaczy, że coś jest ostro przekombinowane…

komentarz 11 stycznia 2016 przez ScriptyChris Mędrzec (190,190 p.)
edycja 11 stycznia 2016 przez ScriptyChris

Przy this.first(this.foo); pojawia się komunikat, ze "foo is not a function", co jest dziwne.

Ale uruchomiło się przy obj.first(obj.foo).

[edit]

Konkretnie, to uruchomiło się, przy zastosowaniu obu technik:

if (callback)
{
   callback.call(this);
}

///////////////

obj.first(obj.foo);

Ale jak musisz konstruować takie rzeczy, to znaczy, że coś jest ostro przekombinowane…

Czy da się to jakoś uprościć?

komentarz 11 stycznia 2016 przez Comandeer Guru (599,730 p.)
Ale ja nie wiem, czy to się da uprościć, bo wgl nie powiedziałeś co chcesz osiągnąć taką konstrukcją.
komentarz 11 stycznia 2016 przez ScriptyChris Mędrzec (190,190 p.)
var obj = {
    setVariables: function(variable)   // funkcja zwracajaca "imitujacje" globalnego scope, dla niektorych zmiennych, obiektu obj{}. Przyjmuje parametr w formie string - zwraca gotowa zmienna
   {
       var statesObj = {},
              createStateLinks;
            /* sa tu jeszcze inne zmienne */
      return eval(variable);   // nie wiem czy dobrze wykorzystuje eval(), ale dziala
   }
    

   addScript: function()  // funkcja dodajaca Google Maps API do DOM
   {
       var script = document.createElement('script');
	script.src = "http://maps.googleapis.com/maps/api/js?&callback=obj.launchApi";  // podlaczam API Google Maps, ktore, po zaladowaniu, odpala callback do funkcji uruchamiajacej API
	document.head.appendChild(script); // podpinam skrypt z pobraniem API do DOM
   },

  launchApi: function(callback)  // uruchomienie API poprzez callback ze skryptu wyzej
  {
       var startMap = function(adres)   // funkcja laduje dane Google Maps
       {
           /* kod funkcji */
       }
       startMap(adres);  // wywolanie
 
      this.getReverseGeocodingData = function (lat, lng, stateO)  // funkcja przyjmuje (z GPS) szerokosc, dlugosc i obiekt, w ktorym sa nazwy wojewodztw
     {
         /* kod funkcji */
     }
     
     if (callback)
      {
         callback.call(this); // funkcja getReverseGeocodingData() ma zostac uruchomiona z callbacka, gdy zostanie zapelniony obiekt statesObj{} - bo z niego bedzie czerpac dane
      }
  },

  fetchStates: function() // funkcja pobiera, poprzez AJAX, dane z zewnetrznej strony internetowej
  {
     /* AJAX, ktory pobiera informacje o wojewodztwach, w ktorych znajduja sie stacje paliwowe */

     // w funkcji AJAX (wewnatrz 'success: function (data, textStatus, jqXHR)") znajduje sie to co nizej
    var createStateLinks = obj.setVariables('createStateLinks'); // pobranie "globalnej" zmiennej, aby byla funkcja dostepna wewnatrz obiektu obj{};
   createStateLinks = function()
   {
      /* funkcja createStateLinks() ma ogolnie zapelnic obiekt statesObj{} (ustawiony jako "globalna" zmienna dla tego obiektu poprzez funkcje setVariables()) nazwami wojewodztw wraz z ich ID (potrzebne do budowania linkow GET */
       
        statesObj = ...  // tutaj do "globalnego" obiektu wkladam ID oraz nazwe poszczegolnych wojewodztw
   }
   createStateLinks(); // wywoluje funkcje zapelniajaca obiekt statesObj{};
   obj.launchApi(obj.getReverseGeocodingData(this.lat, this.lng, this.statesObj)); // uruchamiam, poprzez callback, funkcje ktora ma porownac wojewodztwo w ktorym obecnie jest user (na podstawie uzyskanych jego wspolrzednych GPS - robota Google API) z wojewodztwami z obiektu statesObj{} i jesli znajdzie, to wie w ktorym wojewodztwie ma szukac stacji paliwowych
  }
}
obj.addScript();  // wywoluje funkcje dodajaca skrypt z Google API do DOM
obj.fetchStates(); // wywoluje funkcje pobierajaca informacje o stacjach paliwowych we wszystkich wojewodztwach

 

Streszczony kod mojej aplikacji, bo całość jest za długa, aby wklejać. Generalnie chce wywołać funkcję getReverseGeocodingData() poprzez callback - ponieważ chce aby funkcja createStateLinks() zdazyla zapelnic obiekt statesObj{} potrzebny funkcji getReverseGeocodingData() do dzialania.

Czy można to jakoś uprościć? Bo ogólnie, to jest tylko wywołanie funkcji w innym scope, podczas gdy wszystkie są wewnątrz jednego obiektu obj{};, czyli chyba nierzadko spotykane zjawisko w JS?

komentarz 11 stycznia 2016 przez Comandeer Guru (599,730 p.)

W tego typu kodzie obj.getReverseGeocodingData jest wywoływane PRZED przekazaniem do obj.launchApi (bo Ty przekazujesz WYWOŁANIE funkcji – czyli de facto jej wyniki – nie samą funkcję!). Z tego prosty wniosek, że nie bardzo ma to prawo działać.

Czemu tej funkcji nie zadeklerujesz normalnie, jako metodę obiektu obj?

komentarz 12 stycznia 2016 przez ScriptyChris Mędrzec (190,190 p.)

Upakowałem wszystko w IIFE, a w nim: na początku deklaruje zmienne dla całego scope IIFE; niżej robię funkcję main(), w której umieszczam wszystkie funkcje - każda ma swój scope, w niektórych korzystam ze zmiennych ("globalnych") od IIFE. Wywołanie przez callbacki działa.

Chyba o to mnie chodziło od początku, tylko że przy zapisie z obiektem obj to wywoływanie przez callback nie do końca funkcjonuje i nie umiałem ustawić zmiennych dla całego scope obj.

Czy to jest możliwe tylko przy użyciu funkcji typu "wrapper" (jak main()), że można na poczatku deklarować zmienne, z których korzysta każda funkcja wewnątrz jej?

(function ()
{
   var ... // deklaruje wszystkie zmienne, ktore chce aby byly widoczne w funkcji main

   var main = function(callback)
   {
       /* wszystkie funkcje deklaruje tutaj jako var = function(){}; */

        if (typeof(callback) === 'function') // gdy main() przyjmie callback
	{
 	  callback();
        }
   };
  main(); // wywoluje funkcje main, aby funkcje w srodku byly zadeklarowane (nie byly 'undefined')
  main(foo); // wywoluje co chce przez callback;
}());

 

komentarz 12 stycznia 2016 przez Comandeer Guru (599,730 p.)
Powinno działać bez problemu.

Podobne pytania

0 głosów
0 odpowiedzi 125 wizyt
pytanie zadane 14 grudnia 2020 w JavaScript przez Wiciorny Ekspert (269,120 p.)
0 głosów
1 odpowiedź 598 wizyt
pytanie zadane 1 marca 2019 w PHP przez niezalogowany
0 głosów
0 odpowiedzi 867 wizyt

92,454 zapytań

141,262 odpowiedzi

319,089 komentarzy

61,854 pasjonatów

Motyw:

Akcja Pajacyk

Pajacyk od wielu lat dożywia dzieci. Pomóż klikając w zielony brzuszek na stronie. Dziękujemy! ♡

Oto polecana książka warta uwagi.
Pełną listę książek znajdziesz tutaj.

Akademia Sekuraka

Akademia Sekuraka 2024 zapewnia dostęp do minimum 15 szkoleń online z bezpieczeństwa IT oraz dostęp także do materiałów z edycji Sekurak Academy z roku 2023!

Przy zakupie możecie skorzystać z kodu: pasja-akademia - użyjcie go w koszyku, a uzyskacie rabat -30% na bilety w wersji "Standard"! Więcej informacji na temat akademii 2024 znajdziecie tutaj. Dziękujemy ekipie Sekuraka za taką fajną zniżkę dla wszystkich Pasjonatów!

Akademia Sekuraka

Niedawno wystartował dodruk tej świetnej, rozchwytywanej książki (około 940 stron). Mamy dla Was kod: pasja (wpiszcie go w koszyku), dzięki któremu otrzymujemy 10% zniżki - dziękujemy zaprzyjaźnionej ekipie Sekuraka za taki bonus dla Pasjonatów! Książka to pierwszy tom z serii o ITsec, który łagodnie wprowadzi w świat bezpieczeństwa IT każdą osobę - warto, polecamy!

...