Prośba o sprawdzenie kodu

Prośba o sprawdzenie kodu
adams0
  • Rejestracja:prawie 8 lat
  • Ostatnio:8 dni
  • Postów:316
0

Cześć!
Z nieznanego mi powodu mój programik ze zgadywaniem kolorów nie działa jak należy.
Niezależnie od tego co odpowiem nie widzi odpowiedzi w tablicy.
Pomożecie? :-)

Kopiuj
var target
var answer
var x
var y
var finished = false
kolory = ["pomarańczowy", "żółty", "niebieski", "granatowy", "biały", "czerwony", "morelowy", "błękit", "czarny", "szary"]
kolory.sort()
function gra() {losuj(); pytaj();}
function losuj() {var x = Math.random() * kolory.length; 
	              target = Math.floor(x) + 1}

function pytaj() {while (!finished) {
	var answer = prompt("Jak myślisz...\n jaki kolor wymyślił komputer?\n Masz do wyboru:\n pomarańczowy, żółty, niebieski, granatowy, biały, czerwony, morelowy, błękit, czarny, szary");
	 var finished = sprawdzaj()}
}
function sprawdzaj () {if (kolory.indexOf(answer) > kolory.indexOf(target)) 
	               {alert("Twoja odpowiedz jest alfabetycznie za wysoko"); return false}
	               else if (kolory.indexOf(answer) < kolory.indexOf(target))
	               	{alert("Twoja odpowiedz jest alfabetycznie za nisko"); return false}
	               else if (kolory.indexOf(answer) == -1 )
	               	{alert("Tego nie ma na liście"); return false}
	               else {alert("Brawo trafiłeś!"); return true}
}
bartk
  • Rejestracja:prawie 8 lat
  • Ostatnio:ponad 7 lat
  • Lokalizacja:UK
  • Postów:25
0

proste :-)

w metodzie pytaj() tworzysz nową (var), lokalną zmienną answer, więc ta globalna z początku pliku nie jest aktualizowana bo JS jej już nie widzi.
Usuń var wewnątrz metody i ten sam problem wyszedłby Ci niedługo zresztą co do zmiennej finished.


edytowany 2x, ostatnio: bartk
Shizzer
  • Rejestracja:prawie 8 lat
  • Ostatnio:5 miesięcy
  • Postów:231
0

Ogólnie w JavaScript należy unikać zmiennych globalnych, czyli takich, które deklarujesz poza funkcjami. Chodzi o to, że deklarując zmienne globalne narażasz się na błędy związane z powtórnym używaniem ich nazw do deklaracji nowych zmiennych, ale już wewnątrz funkcji co jest skutkiem pogubienia się w kodzie, a w efekcie właśnie takiego błędu jaki Ty zrobiłeś.


Maciej Cąderek
Maciej Cąderek
To raczej mało ważny powód dlaczego nie należy używać zmiennych globalnych. Brak zmiennych globalnych zresztą nie wyklucza przesłaniania zmiennych (co samo w sobie nie jest zawsze wadą). Zmienne globalne (upraszczając) są złe ponieważ umożliwiają modyfikowanie stanu aplikacji z dowolnego miejsca, funkcje ich używające przestają być przewidywalne i łatwo testowalne (efekty uboczne). Cięzko śledzić zmiany stanu programu (co ma kolosalne znaczenie przy debugowaniu). Samo to, że OP sobie tu coś przesłonił wynika raczej z niezrozumienia działania scope'a.
LukeJL
i to jest argument właśnie za używaniem zmiennych globalnych na początku przygody z programowaniem. Scope w JS (szczególnie var jest dość zamotaną rzeczą) i zmienne globalne prędzej go uchronią od błędów, jak będzie pisał tego typu malutkie programiki.
LukeJL
w sensie, że ta porada "nie używaj zmiennych globalnych" jest dobra ogólnie rzecz biorąc, ale w tym przypadku trochę nieadekwatna moim zdaniem.
Maciej Cąderek
Maciej Cąderek
@LukeJL Tak, co do kodu OP to ja bym się nie czepiał (tam są bardziej podstawowe problemy), co najwyżej pokazał alternatywę (chociaż wiele z tych globali jest zupełnie niepotrzebnych, można je zastąpić returnami bez komplikowania kodu).
LukeJL
@Maciej Cąderek: co do tamtego co pisałeś wyżej - to myślę, że zależy ile jest tych zmiennych globalnych. Dobry singleton nie musi być zły.
LukeJL
np. jeśli masz aplikację opartą o przesyłanie eventów (np. z użyciem Reduxa) to i tak główny event dispatcher musi być dostępny w całej aplikacji, czyli de fakto globalny (nawet jeśli zmienna nie będzie globalna, tylko przekazywana do komponentów, to i tak wychodzi na to, że masz 1 globalny obiekt, za pomocą którego możesz robić wszystko wszędzie).
LukeJL
ale myślę, że kluczem jest to właśnie, że będzie to w ściśle określonym miejscu (i być może w ścisle określonym czasie, jeśli np. eventy będą dodawane do jakiejś kolejki i dopiero potem w odpowiednim czasie odpalane). I dzięki temu w sumie mając globalny obiekt, nie czuje się tego całego zła, w postaci shared mutable state
Maciej Cąderek
Maciej Cąderek
Jeśli mówisz o action dispatcherze to jest to niezmienna funkcja, czyli raczej stała globalna (bo nikt rozsądny jej nie nadpisuje) - zupełnie inna kategoria.
LukeJL
Jej nikt nie nadpisuje, ale jest to funkcja, której wywołanie zmienia globalny stan. Więc jest paradoks, bo z jednej strony mamy globalny stan, który każdy może zmienić, ale z drugiej strony nic się nam nie dzieje, bo nawet jak zmieni, to wiemy dokładnie co się stało i możemy zareagować jakoś.
LukeJL
czyli np. powiedzenie "shared mutable state is the root of all evil." wydaje się być prawdziwe tylko jeśli nie panujemy nad mutacjami. Jeśli natomiast panujemy nad mutacjami i możemy je skontrolować i rozesłać notyfikację do obiektów, że coś się zmieniło - to wydaje się, że już to powiedzenie nie obowiązuje tak specjalnie.
Maciej Cąderek
Maciej Cąderek
Ale w Reduksie stan nie jest globalny, nie można go zmienić bez pośrednictwa store'a.
LukeJL
zapośredniczenie nie zmienia faktu globalności, szczególnie, że ten stan można sobie w każdej chwili odczytać za pomocą funkcji store.getState(). Więc w każdej chwili w dowolnym miejscu ktoś może odpalić funkcję dispatch i zmienić stan, i w każdej chwili ktoś może wywołać getState i uzyskać ten stan. Wydaje mi się, że główna różnica między Reduxem, a zwykłym obiektem globalnym jest pewnego rodzaju reaktywność, że po każdej zmianie stanu w Redux zaktualizują się widoki.
Maciej Cąderek
Maciej Cąderek
Store może być globalny, state stora nie jest zmienną globalną. Nie stosuj wymiennie pojęć. "Reaktywność" nie jest cechą Reduksa - Reduksa można z powodzeniem używać bez Reacta (czy innej biblioteki do widoków), stąd react-redux to osobna biblioteka.
LukeJL
no dobra, zamiast "widoki" podstaw sobie "obserwatorzy, którzy podali do funkcji store.subscribe swój callback" :)
LukeJL
no właśnie nie jestem pewien co to jest ta cała reaktywność. Niby to Mobx jest reaktywny a nie Redux, ale dla mnie i Redux jest reaktywny skoro po aktualizacji stanu są powiadamiani obserwatorzy i (jeśli używamy np. Reacta) odświeżają się widoki. Nie wiem, może źle łapię ten cały koncept reaktywności, ale dla mnie to po prostu wzorzec obserwatora (z którego korzysta Redux).
AG
  • Rejestracja:ponad 7 lat
  • Ostatnio:ponad 7 lat
  • Postów:77
0
Kopiuj
prompt("Jak myślisz...\n jaki kolor wymyślił komputer?\n Masz do wyboru:\n pomarańczowy, żółty, niebieski, granatowy, biały, czerwony, morelowy, błękit, czarny, szary");

Możesz zamienić na

Kopiuj
prompt("Jak myślisz...:\n"+kolory.join('\n'))

Przedmówcy mają rację, unikaj zmiennych globalnych.

adams0
  • Rejestracja:prawie 8 lat
  • Ostatnio:8 dni
  • Postów:316
0

Po usunięciu wszystkich zmiennych globalnych (poza finished) działa jeszcze gorzej.
Zmieniałem globalne i lokalne w różnych konfiguracjach i nie znalazłem opcji żeby zaczęło działać poprawnie.

AG
  • Rejestracja:ponad 7 lat
  • Ostatnio:ponad 7 lat
  • Postów:77
0

wrzuć to np. na https://plnkr.co

Shizzer
  • Rejestracja:prawie 8 lat
  • Ostatnio:5 miesięcy
  • Postów:231
0

Pokaż kod


adams0
  • Rejestracja:prawie 8 lat
  • Ostatnio:8 dni
  • Postów:316
0

Pozbyłem się zmiennych globalnych ale dalej nie działa:

Kopiuj
//var target
//var answer
//var x
//var y
//var finished = false
kolory = ["pomarańczowy", "żółty", "niebieski", "granatowy", "biały", "czerwony", "morelowy", "błękit", "czarny", "szary"]
kolory.sort()
function gra() {losuj(); var finished = false; pytaj();}
function losuj() {var x = Math.random() * kolory.length; 
                  target = Math.floor(x) + 1}
 
function pytaj() {while (!finished) {
	var answer = prompt("Jak myślisz...\n Jaki kolor wymyślił komputer?\n Masz do wyboru:\n" + kolory.join('\n'));
     var finished = sprawdzaj()}
}
function sprawdzaj () {if (kolory.indexOf(answer) > kolory.indexOf(target)) 
                   {alert("Twoja odpowiedz jest alfabetycznie za wysoko"); return false}
                   else if (kolory.indexOf(answer) < kolory.indexOf(target))
                    {alert("Twoja odpowiedz jest alfabetycznie za nisko"); return false}
                   else if (kolory.indexOf(answer) == -1 )
                    {alert("Tego nie ma na liście"); return false}
                   else {alert("Brawo trafiłeś!"); return true}
}
AG
  • Rejestracja:ponad 7 lat
  • Ostatnio:ponad 7 lat
  • Postów:77
0

teraz np. answer jest widoczna tylo w pytaj, więc nie masz jej dostępnej w sprawdzaj(), możesz ją dodać do sprawdzaj(answer).
Przeanalizuj sobie, gdzie która zmienna jest potrzebna.
Korzystaj też z podpowiedzi dev toolsów.
Wrzuciłem to na https://plnkr.co/edit/fVv9xGuy0Xo5e11ak5HY?p=preview.

Shizzer
  • Rejestracja:prawie 8 lat
  • Ostatnio:5 miesięcy
  • Postów:231
0

Poczytaj o zmiennych lokalnych i o przysłanianiu zmiennych globalnych, a także o funkcjach pierwszej klasy. Zrozum dobrze te tematy i rozpisz sobie logikę tego programu gdzieś na kartce, czyli co się po kolei wykonuje, a następnie popraw kod. Zwracaj też uwagę na błędy, które pokazuje Ci przeglądarka w konsoli - dzięki nim łatwiej Ci będzie dojść do ładu.


edytowany 1x, ostatnio: Shizzer
LukeJL
  • Rejestracja:około 11 lat
  • Ostatnio:30 minut
  • Postów:8423
0

Ogólnie w JavaScript należy unikać zmiennych globalnych, czyli takich, które deklarujesz poza funkcjami.

Rada o usuwaniu zmiennych globalnych była raczej kulą w płot, bo OP właśnie chce zrobić zmienną globalną (czy raczej: widoczną w wielu funkcjach), więc idąc za tą radą pozbawił się możliwości komunikacji między funkcjami. Tę radę należy jednak uzupełnić o zaprezentowanie innego rozwiązania (co zamiast zmiennych globalnych), czyli np. przekazywanie argumentów do funkcji:

Kopiuj
someFunction(someArgument) {
   // mamy dostep do zmiennej someArgument w funkcji
}
...
someFunction(23); //podanie 23 jako someArgument

Ale z drugiej strony w małym programie zmienne globalne nie są aż tak bardzo szkodliwe, wystarczy je otoczyć w jakieś IIFE (albo w moduł CommonJS / ES6) , żeby nie zaburzały globalnej przestrzeni nazw i myślę, że często będzie mieć to więcej sensu niż bawienie się w podawanie argumentów wszędzie. Szczególnie jak ktoś zaczyna to zmienne globalne są bardziej przewidywalne jednak od rozgryzania zasięgów zmiennych w JS.


edytowany 1x, ostatnio: LukeJL
Maciej Cąderek
Maciej Cąderek
  • Rejestracja:ponad 9 lat
  • Ostatnio:ponad 3 lata
  • Lokalizacja:Warszawa
  • Postów:1264
0

Masz tu rozwiązanie bez globali (jest tylko globalna "stała" - tablica kolorów), mozna to zrobić dużo lepiej, ale nie chcę mieszać:

Kopiuj
var KOLORY = [
  "biały",
  "błękit",
  "czarny",
  "czerwony",
  "granatowy",
  "morelowy",
  "niebieski",
  "pomarańczowy",
  "szary",
  "żółty",
]

function gra() {
  var answer
  var finished = false
  var targetIndex = losuj(KOLORY.length)
  
  while (!finished) {
    answer = pytaj()
    finished = sprawdzaj(answer, targetIndex)
  }
}

function losuj(max) {
  var x = Math.random() * max;
  
  return Math.floor(x) + 1
}

function pytaj() {
  return prompt(
    "Jak myślisz...\n jaki kolor wymyślił komputer?\n Masz do wyboru:\n" +
    KOLORY.join(', ')
  )  
}

function sprawdzaj (answer, targetIndex) {
  var answerIndex = KOLORY.indexOf(answer)
  
  if (answerIndex === targetIndex) {
    alert("Brawo trafiłeś!")
    return true
  }
  
  if (answerIndex === -1 ) {
    alert("Tego nie ma na liście")
  } else if (answerIndex > targetIndex) {
    alert("Twoja odpowiedz jest alfabetycznie za wysoko")
  } else {
    alert("Twoja odpowiedz jest alfabetycznie za nisko")
  }
  
  return false
}

CodePen: https://codepen.io/caderek/pen/vJGpxV?editors=0010

Przeanalizuj, w razie czego pytaj (btw miałeś skopaną kolejność ifów, dodatkowo kolory.indexOf(target) to bezsens, bo target u Ciebie to już indeks).

edytowany 8x, ostatnio: Maciej Cąderek
LukeJL
w sumie tu można jeszcze wydzielić stringi "Tego nie ma na liście" itp. do zmiennej, żeby potem tylko raz wywoływać alert.
HA
  • Rejestracja:około 10 lat
  • Ostatnio:ponad 7 lat
  • Postów:335
0

Przy okazji wykombinowaliście prompta, którego można zamknąć tylko przez zgadnięcie koloru - przycisk anuluj nie spełnia swojej roli :)

Maciej Cąderek
Maciej Cąderek
No już w sam sens rozgrywki i "interfejsu" nie wnikałem :P
LukeJL
  • Rejestracja:około 11 lat
  • Ostatnio:30 minut
  • Postów:8423
0

Nie wiem czy kiedykolwiek w realnej aplikacji użyłem prompta XD Kojarzy mi się to głównie ze spamerskimi stronami typu "Wygrałeś iPhona". W sumie bardzo rzadko się to przydaje (jedyny use case jaki mi przychodzi, to coś jak na Facebooku i Gmailu jest - że jeśli zaczniesz piszesz posta i będziesz chciał wyjść, to wyskoczy ci okienko o tym, czy naprawdę chcesz wyjść ze strony, jeśli masz niezapisane zmiany).

Jednak to są rzadkie przypadki i generalnie lepiej użyć zwykłych buttonów czy całych formularzy do tego typu rzeczy, niż gwałcić użytkownika (modalne okna to gwałt na użytkowniku, jakby nie było)


edytowany 1x, ostatnio: LukeJL
bartk
  • Rejestracja:prawie 8 lat
  • Ostatnio:ponad 7 lat
  • Lokalizacja:UK
  • Postów:25
0

Tylko po co robić Offtop. Kolega uczy się JS i ma problem (jak każdy na tym etapie) ze zrozumieniem działania scope w JS.
Prompty są złe, globalne są złe ale nie wszystko na raz, lepiej uczyć się krok po kroku.


edytowany 2x, ostatnio: bartk
adams0
  • Rejestracja:prawie 8 lat
  • Ostatnio:8 dni
  • Postów:316
0
Maciej Cąderek napisał(a):

Masz tu rozwiązanie bez globali (jest tylko globalna "stała" - tablica kolorów), mozna to zrobić dużo lepiej, ale nie chcę mieszać:

Kopiuj
(...)
function losuj(max) {
  var x = Math.random() * max;
  
  return Math.floor(x) + 1
}
( ...)
Kopiuj

Tak sobie na to patrze i myślę że ta funkcja nigdy nie wylosuje wartości 0, czyli koloru białego.
Do tego czasem losuje wartość z poza tablicy.
Czy nie lepsze byłoby:

Kopiuj
function losuj(max) {
var x = Math.random() * max;
return Math.floor(x)

?

edytowany 1x, ostatnio: adams0
HA
Post popraw, bo kodu się czytać nie da ;)
Maciej Cąderek
Maciej Cąderek
  • Rejestracja:ponad 9 lat
  • Ostatnio:ponad 3 lata
  • Lokalizacja:Warszawa
  • Postów:1264
0

@adams0
Możliwe, nie sprawdzałem działnia tej funkcji, przepisałem Twoją.

Zarejestruj się i dołącz do największej społeczności programistów w Polsce.

Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.