2011-03-02 13 views
5

Tengo dificultades para seguir esta función. No entiendo cómo la variable start revierte a 16 después de que alcance un valor de 26, que es mayor que 24.Explicar esta función de JavaScript de Eloquent Javascript

function findSequence(goal) { 
    function find(start, history) { 
    if (start == goal) 
     return history; 
    else if (start > goal) 
     return null; 
    else 
     return find(start + 5, "(" + history + " + 5)") || 
      find(start * 3, "(" + history + " * 3)"); 
    } 
    return find(1, "1"); 
} 

print(findSequence(24)); 

bien, después de mirar esto por algún tiempo, tengo un par de preguntas que podría aclarar un algunas cosas:

1) ¿Es una afirmación correcta decir que cada llamada a buscar realiza un seguimiento de su propio valor de inicio? Por ejemplo, cuando se llama a find (1), tiene un valor de inicio de 1, cuando se llama a find (1 + 5), el valor de inicio de find (1) sigue siendo uno, pero find (1 + 5) ahora tiene es su propio valor inicial de 6.

2) Me está costando mucho seguir la pila, incluso si la veo impresa. Esta es la forma en que estoy viendo que:

find (1) llama a encontrar (1 + 5) = 1 // Iniciar

find (6) llamadas a encontrar (6 + 5) // start = 6, pases

find (11) se encuentran las llamadas (11 + 5) // start = 11, pasa

find (16) llamadas a encontrar (16 + 5) // start = 16, pasa

find (21) llamadas find (21 + 5) // start = 21, Fails

Beca use find (21 + 5) devuelve null, intenta llamar a find (21 * 3) que también devuelve null.

Esta es la parte en la que me quedo atascado, si ambos encuentran (21 + 5) y encuentran (21 * 3) devuelven nulo, ¿cómo sabe llamar a find (16 * 3) después? ¿Por qué no encuentra (16 + 5) nuevamente?

Tiene algo que ver cuando find (21 + 5) y find (21 * 3) fueron llamados por find (16) y porque aquéllos devolvieron null a la función de llamada, ejecutó la segunda parte || declaración que fue encontrar (16 * 3).

+1

¿No significan dos tubos "o"? ¿Cómo puedes devolver una cosa u otra? – ScottC

+0

@ScottC: en Javascript, "O" '||' devuelve el primer elemento si es verdadero-ish, o el segundo elemento si el primer elemento es falso-ish (que incluye null). Es una generalización del booleano o se comporta de manera similar a un operador de coalescencia nula. – Jimmy

+0

@ScottC: Lea el capítulo de su libro de Javascript sobre condiciones booleanas. Es lo mismo que 'var x = y || z; devolver x; '. –

Respuesta

2

Es una variable diferente. comienza cada vez que se llama a un find particular (x), su valor de inicio no afecta a ninguna otra instancia de inicio.

cuando find (21) se llama, se devuelve un valor nulo, debido a find (26) y encontrar (63) vuelven nula asimismo, find (16) y encontrar (11) vuelven nula

cuando find (6) se llama, llama a find (11), que devuelve null, por lo que llama a find (24) a continuación. en el contexto de la presente convocatoria, inicie == 6, por lo que continúa con arranque + 5 y empezar * 3.

find(6): 
start = 6, history = (1 + 5) 
    find(6 + 5): 
    start = 11, history = ((1 + 5) + 5) 
     find(11 + 5): 
     start = 16, history = (((1 + 5) + 5) + 5) 
     ... continued etc... 

     find(11 * 3): 
     start = 33, history = (((1 + 5) + 5) * 3) 
     <end> 
    find(6 * 3): 
    start = 24, history = ((1 + 5) * 3) 
+0

Acepto, las nuevas instancias de find contienen nuevas instancias de inicio e historial, quizás en lugar de pasando la variable ByVal javascript tiene una forma de pasar ByRef ?? como C++? si eso es de hecho lo que está tratando de lograr – ScottC

+0

bien, la función indicada es correcta. Xaisoft simplemente parece pensar que hay un único contexto de búsqueda (hay múltiples). Compare con "hay un contexto único de findSequence, y por lo tanto un único valor para el objetivo" (que es verdadero) – Jimmy

2

Usted no está teniendo en cuenta que las ramas de recursividad a cabo. Puede parecer que los nervios comienzan a subir y bajar, pero solo está llegando al final de un árbol de recursión y se salta a uno diferente.

Trabajando a través de las llamadas:


Valores de start en el árbol de la recursividad (ramificación en start+5/start*3):

     1 
       6---------+----------3 
     11----+--18   8-----+----- 
    16-+-33 23-+--48 13-+--24 
    21-+-80 28+69  18+39 
26+63    23+90 
        28+69 

Ver cómo termina cada rama cuando el valor sube demasiado, entonces el valor de start que ve baja mientras el procesamiento salta a la siguiente rama hacia la derecha. El procesamiento se detiene cuando se encuentra el '24 '.


:

+0

es una búsqueda en profundidad que se detiene cuando start> goal, por lo que find (26) ocurre antes de que find (24) ocurra , que es lo que confunde a Xaisoft. – Jimmy

+0

@Jimmy: No se detiene cuando 'start> goal', se detiene cuando' start == goal'. Cuando 'start> goal' se abandona el árbol actual, pero aún se buscan otros. –

+0

sí, la confusión en la pregunta se debe a que él piensa que solo hay un valor de inicio. – Jimmy

6

Tal vez no estás del todo convencido, pero lo tienes (Negación No he comprobado plenamente todas las matemáticas, pero el principio debería estar en buen estado!).

En cuanto a la pregunta 1, es correcto decir que los valores de start se conservan a lo largo de las llamadas internas. Es como si cada llamada tuviera su propio "contexto": incluso si modifica las variables y los valores de los argumentos, esto no se lleva a la llamada de función externa. Ese es el alcance.

La pregunta 2 parece estar relacionada con la evaluación booleana de cortocircuitos. El comportamiento es exactamente el que describió: una vez que la expresión a la izquierda del operador || devuelve algo "verdadero", la expresión de la derecha no se evaluará. Y lo contrario también es cierto: si la expresión izquierda es "falsey", entonces el intérprete procederá a evaluar la expresión correcta. El valor resultante será el primer valor que no sea falsey o el último valor de la cadena.

¡Así que creo que tienes todo cubierto!


He alterado el guion original para que imprima un rastro de llamada. Véalo en acción here.

Esta es una traza parcial donde el valor de start parece "disminuir" a 16 después de que va más allá:

enter image description here

La función va un poco más bajo la 16 rama, entonces se desiste, volviendo a la llamada superior donde start es 11. Luego procede a probar un valor de 11 * 3 para start, luego desiste de nuevo, y así sucesivamente.

+0

Impresionante, estoy caminando a mano y probablemente actualice mi pregunta porque creo que la estoy obteniendo, pero todavía no. – Xaisoft

Cuestiones relacionadas