Tiendo a pensar en términos de características:
Sintaxis:
Basado en C o lo que tienes. Java tiene una sintaxis basada en C. Recomiendo probar algo como Python o Ruby para sacar la cabeza de la sintaxis y pensar más en términos de los fundamentos de cómo funciona un lenguaje determinado. Soy de la opinión de que ninguna sintaxis necesita ser más voluminosa que la basada en C y no tener problemas para construir bloques alrededor del espacio en blanco.
Compilado vs. interpretado w. Proceso de compilación vs. Interpretado / Consola:
Tengo muy poca familiaridad con las preocupaciones sobre el tiempo de compilación frente al entorno de tiempo de ejecución, pero entiendo que hay una gran cantidad de preocupaciones allí en las que rara vez pienso.
Del mismo modo, hay muchos lenguajes interpretados que todavía tienen algo de un proceso de compilación para ejecutarse dentro de una máquina virtual como Java. Todavía tiene que reconstruir para ver cambios en las cosas.
Y luego está JavaScript y Python que puede ejecutar sobre la marcha, comando por comando en una consola en un entorno en vivo. Los tres pueden conducir a formas muy diferentes de escribir código.
Escritura dinámica versus estricta:
Tiendo a ver los dos como compensaciones de diseño. Cuando se encuentra en un nivel mucho más bajo y el rendimiento es crítico, la escritura estática tiene mucho sentido. Nunca he entendido esta noción de que uno sea "más seguro" que otro de alguna manera, pero surgió en un lenguaje muy plástico / dinámico donde simplemente aprendes cómo funciona el sistema de mecanografía y qué esperar, básicamente. Las travesuras de tipo rara vez son una preocupación para mí en JS. De alguna manera, la flexibilidad puede hacer que las cosas sean más robustas, aunque ciertamente es un poco más arcano para un desarrollador de nivel Jr. más si no conoce algunos de los baches en el idioma.
Alcance de nivel de bloque vs. Alcance de función vs.
Block-Level es el más común (cualquier cosa entre {} en la mayoría de los lenguajes de sintaxis basados en c). El alcance de JavaScript se basa en funciones (que también se utilizan para construir objetos de manera tan efectiva). También hay una gran variación en el tipo de acceso que tiene desde el ámbito interno a un ámbito externo. No estoy familiarizado con otros esquemas de alcance, pero estoy seguro de que existen.
OOP clásica versus OOP prototípica versus casi OOP (estructuras en C?) Vs no OOP:
Incluso en la OOP basada en la clase, hay mucho margen de variación. Si puede hacer herencia múltiple (ew, bien en exceso, ew), definir interfaces, etc.
En JavaScript tenemos una especie de OOP prototípica atrofiada donde los objetos son considerablemente más simples, altamente mutables, pero aún tenemos la capacidad de separar la interfaz de las preocupaciones internas, lo cual es el aspecto importante de la encapsulación.
Lo que pasa con OOP es que realmente hay muchas cosas que puedes lograr que están esencialmente orientadas a OOP sin ser técnicamente OOP. Hay puristas, por supuesto, pero al final del día, los patrones de diseño tratan de lograr ciertas abstracciones que funcionan bien en ciertas situaciones. No se apresure a asumir que las ideas de un lenguaje basado en OOP no tienen uso en algo que esté más orientado a los procedimientos. Y no estoy hablando de JavaScript. No está limitado en absoluto por su versión tonta de un paradigma basado en prototipos OOP.
Funciones de primera clase:
No tenerlos en un idioma es algo difícil de abandonar. Puede pasar funciones como si fueran datos para usar en otros contextos. Esto hace que los esquemas de manejo de eventos en particular sean muy fáciles de implementar, pero también hace que sea muy fácil adaptar el lenguaje para que funcione de la manera que le gustaría. Es, más que nada, lo que sospecho, lo que ha hecho que JavaScript sea el éxito, a pesar de haber sido diseñado en dos semanas y obtener una sintaxis aproximada de Java como un esquema de marketing.
Cierres:
No estoy seguro de dónde está el debate para Java, pero sé que muchos desarrolladores de Java estaban clamando por esta característica hace uno o dos años. En un lenguaje sin cierre, cuando una función se cierra, cualquier cosa que de alguna manera pueda hacer referencia a cosas desde dentro de esa función no podrá acceder a ella porque se recogió basura. En un cierre, el contexto de ejecución está limitado de tal manera que si puede hacer referencia a cosas dentro de esa función cerrada desde otro ámbito, como en un objeto o función devuelto, básicamente obtiene esos vars tal como estaban cuando la función se cerró. Es como meter el pie en la puerta de la recolección de basura, aunque sospecho que se implementa más como copias de esos vars hechos en vars locales de la entidad de referencia.
Rígido / estricto / seguro frente a darle toda la cuerda que desea:
Los desarrolladores de JS y Java tienden a no entenderse entre sí y creo que tiene mucho que ver con los dos idiomas que caen en lados casi opuestos de este espectro de diseño en particular. No quiero que me protejas de mí mismo o de los otros desarrolladores de mi equipo. Quiero hacer mucho más en mucho menos código y hacerlo de maneras muy diferentes (pero consistentes para un dominio dado) dependiendo de la situación. Hay absolutamente compensaciones para ambos y muchos idiomas tienden a caer más en el medio.