2011-02-17 15 views
12

http://ejohn.org/files/pretty.js¿Alguien puede explicar cómo funciona el JavaScript de pretty.js de John Resig?

// Takes an ISO time and returns a string representing how 
// long ago the date represents. 
function prettyDate(time){ 
    var date = new Date((time || "").replace(/-/g,"/").replace(/[TZ]/g," ")), 
     diff = (((new Date()).getTime() - date.getTime())/1000), 
     day_diff = Math.floor(diff/86400); 

    if (isNaN(day_diff) || day_diff < 0 || day_diff >= 31) 
     return; 

    return day_diff == 0 && (
      diff < 60 && "just now" || 
      diff < 120 && "1 minute ago" || 
      diff < 3600 && Math.floor(diff/60) + " minutes ago" || 
      diff < 7200 && "1 hour ago" || 
      diff < 86400 && Math.floor(diff/3600) + " hours ago") || 
     day_diff == 1 && "Yesterday" || 
     day_diff < 7 && day_diff + " days ago" || 
     day_diff < 31 && Math.ceil(day_diff/7) + " weeks ago"; 
} 

// If jQuery is included in the page, adds a jQuery plugin to handle it as well 
if (typeof jQuery != "undefined") 
    jQuery.fn.prettyDate = function(){ 
     return this.each(function(){ 
      var date = prettyDate(this.title); 
      if (date) 
       jQuery(this).text(date); 
     }); 
    }; 

¿cómo es exactamente el método devuelve una cadena de prettyDate()? ¿Es esta otra de esas cosas 'extrañas' que puedes hacer en JavaScript o simplemente me falta algo?

editar: No pregunté cómo devolvía un valor, le pregunté cómo devolvía una cadena.

return day_diff == 0 && (....) devuelve un booleano en cualquier idioma que haya usado alguna vez.

+0

¿Uh, usando la declaración de devolución? En los casos en que solo dice return, ¿el valor es nulo? –

+2

"' && devuelve un booleano en cualquier idioma que haya usado "" - Entonces no ha usado muchos idiomas. ;-) – deceze

+0

No todo comprueba 'verdadero' y 'falso' con valores verdaderos y falsos literales. JavaScript usa los valores "truthy" y "falsey" –

Respuesta

9

es que dice allí: return ... y luego entra en una larga lista anidada de básicamente " en línea ifs ". ;-)

En Javascript, los operadores booleanos devuelven el valor de uno de los operandos, no sólo true o false. P.ej. 0 || 'foo' devuelve 'foo'. Esta característica se usa junto con el cortocircuito del operador. false && true no evaluará el lado true y devolverá false inmediatamente, ya que toda la expresión debe ser false.

+1

Pero más Hasta el punto, este póster probablemente solo haya tenido experiencia con lenguajes tipados estáticamente (el tipo se conoce en todas partes en tiempo de compilación). JavaScript es un lenguaje de tipeo dinámico, lo que significa que las expresiones pueden devolver diferentes tipos en función de las condiciones de tiempo de ejecución. && 5' para devolver '" cat "' y "' null || 32.1' "para devolver' 32.1'. – jpsimons

27

En JavaScript:

  • a || b es equivalente a a ? a : b
  • a && b es equivalente a a ? b : a
  • cualquier cadena no vacía en una expresión booleana es verdadera

Con este conocimiento , la lógica de la declaración de retorno se vuelve bastante directa.

Supongamos, por ejemplo, que day_diff = 5

Luego de tomar la declaración de arriba paso a paso:

return day_diff == 0 && (
     diff < 60 && "just now" || 
     diff < 120 && "1 minute ago" || 
     diff < 3600 && Math.floor(diff/60) + " minutes ago" || 
     diff < 7200 && "1 hour ago" || 
     diff < 86400 && Math.floor(diff/3600) + " hours ago") || 
    day_diff == 1 && "Yesterday" || 
    day_diff < 7 && day_diff + " days ago" || 
    day_diff < 31 && Math.ceil(day_diff/7) + " weeks ago"; 

En primer lugar, day_diff == 0 evaluará a false y el lado derecho:

(diff < 60 && "just now" || 
diff < 120 && "1 minute ago" || 
diff < 3600 && Math.floor(diff/60) + " minutes ago" || 
diff < 7200 && "1 hour ago" || 
diff < 86400 && Math.floor(diff/3600) + " hours ago") 

... no se ha evaluado. Ambos lados de:

day_diff == 1 && "Yesterday" 

... evaluar a false. Cerca hay:

day_diff < 7 && day_diff + " days ago" 

En esta expresión se evalúa como day_diff < 7true, por lo que su lado derecho, que es una cadena, se evaluará y su resultado devuelto.

Más información:

http://www.ejball.com/EdAtWork/2005/02/19/JavaScriptBooleanOperators.aspx

+1

Creo que es más preocupado por la concatenación que ocurre dentro del condicional en la declaración de retorno que con el significado del operador '+' –

+0

Gracias. Eso fue un poco instintivo. Estoy actualizando con algo que espero sea más útil. –

1

Sí, es raro cosas Javascript. La concatenación de cadenas se evalúa como verdadera y la instrucción return en la parte inferior de prettyDate() aprovecha esto más short-circuiting en condicionales.

Básicamente, en el primer caso, diff < 60 && "just now" evalúa la cadena "just now" si diff es de hecho menor que 60 porque todos los demás elementos de nivel superior en el condicional están OR juntos, por lo que el evaluador de Javascript no lo hace no se preocupan por ellos una vez que esta primera condición es verdadera. Lo mismo continúa en la línea.

1

Se está jugando el juego peligroso de depender de precedencia de los operadores para procesar los condicionales:

+ triunfos && el que triunfa sobre ||

Ver: https://developer.mozilla.org/en/JavaScript/Reference/Operators/Operator_Precedence

Ésta es la forma en que lo leí:

(day_diff == 0 && (
      (diff < 60 && "just now") || 
      (diff < 120 && "1 minute ago") || 
      (diff < 3600 && Math.floor(diff/60) + " minutes ago") || 
      (diff < 7200 && "1 hour ago") || 
      (diff < 86400 && Math.floor(diff/3600) + " hours ago") 
     )) || 
     (day_diff == 1 && "Yesterday") || 
     (day_diff < 7 && day_diff + " days ago") || 
     (day_diff < 31 && Math.ceil(day_diff/7) + " weeks ago"); 
1

La última declaración de la línea tiene el forma

return boolExpression && otherBoolExpression 

Cuando Javascript lee esto, ocurre lo siguiente:

  1. si boolExpression si Falsey-, devuelve boolExpression
  2. lo contrario, devuelve otherBoolExpression.

Esta es la forma en que JavaScript hace la lógica de cortocircuito.

Dado que, en este caso, otherBoolExpression utiliza un concatenación de cadenas, la función devuelve la cadena, siempre y cuando no dayDiff 0.

2

La declaración de devolución es simplemente una cascada if/else complicada que termina devolviendo una cadena en todos los casos sin errores.

E.g.

return day_diff == 0 && (
     diff < 60 && "just now" || 
     diff < 120 && "1 minute ago" || [...] 

Si day_diff es cero (es decir, la fecha es hoy en día), entonces se cae en la comprobación para ver si es menos de 60. Si esta afirmación es cierta, entonces un cortocircuito en la evaluación del resto de la todo, y devuelve el valor de la expresión, que será "justo ahora". Si diff no es inferior a 60, cortocircuitará la subexpresión y pasará a la verificación diff < 120, y así sucesivamente.

Las cadenas siempre son "verdaderas" en las expresiones, y también se convierten en el resultado de evaluar la expresión cuando ese caso coincide.

Este es un código funcional pero bastante ofuscado. No para fines de enseñanza. :)

0

Hay dos variables: diferencia - diferencia en segundos, díadiff - diferencia en días. Si daydiff es cero, el valor de retorno se basa en diff, de lo contrario es número de días.

Lea el 'retorno' como una serie de cláusulas 'if'/'else' que decide la cadena de retorno.

1

Básicamente sólo hay que saber que

return day_diff == 0 && "lala" + "lolo" 

volverá lalalolo si day_diff == 0 ... debido a la precedencia de operadores.

lo que es sólo un camino más corto para escribir

if (day_diff == 0) { 
    if (diff < 60) { 
     return "just now" 
    } else (...) 
} else { 
    if (day_diff == 1) { 
    return "..." 
    } 
} 
7

¿Eres una persona de Java? Porque si es así, probablemente piense que if(x) necesita que x sea un booleano, y que "x & & y" devuelve un valor booleano. No lo hace en JavaScript y en muchos otros lenguajes como Perl. En muchos lenguajes de tipo débil & & se denomina operador de guardia y || se llama el operador predeterminado. Devuelven uno de sus dos argumentos.

+2

No estoy seguro de por qué los llamas "más evolucionados", porque no lo son, son solo diferente. –

+0

Perdón por el crack "más evolucionado", trabajo con Java todos los días y todavía no puedo creer que tengas que decir 'if (myObject! = Null)' en lugar de 'if (myObject)'. – jpsimons

+0

La forma en que funcionan las operaciones lógicas en JavaScript, Python, Ruby, Perl, etc. simplemente no funcionaría en Java porque los tipos de variables son inmutables. Entonces tienes razón, es simplemente diferente. – jpsimons

Cuestiones relacionadas