Pregunta ¿La palabra clave "nueva" de JavaScript se considera dañina? [cerrado]


En otro pregunta, un usuario señaló que new la palabra clave era peligrosa de usar y propuso una solución para la creación de objetos que no se usaba new. No creía que eso fuera cierto, sobre todo porque utilicé Prototype, Scriptaculous y otras excelentes bibliotecas de JavaScript, y todos usaron el new palabra clave.

A pesar de eso, ayer estaba viendo la charla de Douglas Crockford en el teatro YUI y dijo exactamente lo mismo, que no usó el new palabra clave más en su código (Crockford en JavaScript - Acto III: Funciona lo último - 50:23 minutos)

¿Es 'malo' usar el new ¿palabra clave? ¿Cuáles son las ventajas y desventajas de usarlo?


544
2017-12-20 15:20


origen


Respuestas:


Crockford ha hecho mucho para popularizar buenas técnicas de JavaScript. Su postura obstinada sobre los elementos clave del lenguaje ha suscitado muchas discusiones útiles. Dicho esto, hay demasiadas personas que toman cada proclamación de "malo" o "dañino" como un evangelio, negándose a mirar más allá de la opinión de un hombre. Puede ser un poco frustrante a veces.

Uso de la funcionalidad provista por el new La palabra clave tiene varias ventajas sobre construir cada objeto desde cero:

  1. Herencia del prototipo. Aunque a menudo se lo mira con una mezcla de sospecha y burla por parte de aquellos que están acostumbrados a los lenguajes OO basados ​​en clases, la técnica de herencia nativa de JavaScript es un medio simple y sorprendentemente efectivo de reutilización de códigos. Y la nueva palabra clave es el medio canónico (y solo disponible multiplataforma) de usarlo.
  2. Actuación. Este es un efecto secundario de # 1: si quiero agregar 10 métodos a cada objeto que creo, podría simplemente escriba una función de creación que asigna manualmente cada método a cada nuevo objeto ... O bien, podría asignarlos a la función de creación prototype y use new para eliminar nuevos objetos. Esto no solo es más rápido (no se necesita código para todos y cada uno de los métodos del prototipo), sino que evita que cada objeto tenga propiedades separadas para cada método. En máquinas más lentas (o especialmente, intérpretes JS más lentos) cuando se crean muchos objetos, esto puede significar un ahorro significativo de tiempo y memoria.

Y si, new tiene una desventaja crucial, hábilmente descrita por otras respuestas: si te olvidas de usarla, tu código se romperá sin previo aviso. Afortunadamente, esa desventaja se mitiga fácilmente: simplemente agregue un poco de código a la función en sí:

function foo()
{
   // if user accidentally omits the new keyword, this will 
   // silently correct the problem...
   if ( !(this instanceof foo) )
      return new foo();

   // constructor logic follows...
}

Ahora puedes tener las ventajas de new sin tener que preocuparse por los problemas causados ​​por el mal uso accidental. Incluso podría agregar una afirmación al cheque si le molesta la idea de que el código roto funcione silenciosamente. O, como algunos comentado, use el cheque para introducir una excepción en tiempo de ejecución:

if ( !(this instanceof arguments.callee) ) 
   throw new Error("Constructor called as a function");

(Tenga en cuenta que este fragmento puede evitar codificar el nombre de la función del constructor, ya que a diferencia del ejemplo anterior, no tiene necesidad de crear una instancia real del objeto; por lo tanto, puede copiarse en cada función objetivo sin modificaciones).

John Resig entra en detalles sobre esta técnica en su Simple instanciación de "Clase" publicar, así como también incluir un medio para construir este comportamiento en sus "clases" por defecto. Definitivamente vale la pena leer ... como es su próximo libro, Secretos del JavaScript Ninja, que encuentra oro escondido en esta y muchas otras características "dañinas" del lenguaje JavaScript (el capítulo en with es especialmente esclarecedor para aquellos de nosotros que inicialmente desechamos esta característica muy difamada como un truco).


584
2017-12-20 17:17



Acabo de leer algunas partes de su libro de Crockfords "Javascript: The Good Parts". Tengo la sensación de que considera que todo lo que alguna vez lo ha mordido es dañino:

Acerca del cambio fallido:

Nunca dejo que caigan los conmutadores   hasta el próximo caso. Una vez encontré   un error en mi código causado por un   caída involuntaria inmediatamente   después de haber hecho un discurso vigoroso   acerca de por qué fracasaron algunas veces   útil. (página 97, ISBN   978-0-596-51774-8)

Acerca de ++ y -

++ (incremento) y - (decremento)   los operadores son conocidos por   contribuir al mal código mediante el fomento   exessive trickiness. Ellos son segundos   solo a la arquitectura defectuosa en   habilitando virus y otra seguridad   amenazas (página 122)

Acerca de nuevo:

Si te olvidas de incluir el nuevo   prefijo al llamar a un constructor   función, entonces esta no será   ligado al nuevo objeto. Tristemente, esta   estará ligado al objeto global, por lo   en lugar de aumentar su nuevo objeto,   estarás derrotando globalmente   variables. Eso es realmente malo. Ahí   no es una advertencia de compilación, y no hay   advertencia de tiempo de ejecución. (página 49)

Hay más, pero espero que entiendas la imagen.

Mi respuesta a tu pregunta: No, no es dañino. pero si se olvida de usarlo cuando debería, podría tener algunos problemas. Si se está desarrollando en un buen ambiente, lo nota.

Actualizar

Alrededor de un año después de la redacción de esta respuesta, se lanzó la quinta edición de ECMAScript, con soporte para Modo estricto. En modo estricto, this ya no está vinculado al objeto global sino a undefined.


174
2017-12-20 15:43



Javascript es un lenguaje dinámico que tiene un montón de maneras de cometer un error donde otro idioma podría detenerte.

Evitar una característica fundamental del lenguaje como new sobre la base de que puede estropear es como quitarse los zapatos nuevos y brillantes antes de caminar por un campo minado, en caso de que pueda ensuciar sus zapatos.

Utilizo una convención en la que los nombres de las funciones comienzan con una letra minúscula y las "funciones" que en realidad son definiciones de clase que comienzan con una letra mayúscula. El resultado es una pista visual bastante convincente de que la 'sintaxis' es incorrecta: -

var o = MyClass();  // this is clearly wrong.

Además de esto, los buenos hábitos de nomenclatura ayudan. Después de que todas las funciones hagan cosas y por lo tanto debe haber un verbo en su nombre, mientras que las clases representan objetos y son sustantivos y adjetivos sin verbo.

var o = chair() // Executing chair is daft.
var o = createChair() // makes sense.

Es interesante cómo la coloración de sintaxis de SO ha interpretado el código anterior.


91
2017-12-20 17:10



Soy un novato en Javascript, así que tal vez no tenga demasiada experiencia para proporcionar un buen punto de vista sobre esto. Sin embargo, quiero compartir mi opinión sobre esta "nueva" cosa.

Vengo del mundo de C # donde usar la palabra clave "nuevo" es tan natural que es el patrón de diseño de fábrica lo que me parece extraño.

Cuando codifico por primera vez en Javascript, no me doy cuenta de que existe la palabra clave "nueva" y el código como el que está en el patrón YUI y no me lleva mucho tiempo entrar en un desastre. Pierdo la noción de lo que se supone que debe hacer una línea en particular al mirar hacia atrás el código que he escrito. Más caótico es que mi mente realmente no puede transitar entre límites de instancias de objetos cuando estoy "ejecutando en seco" el código.

Luego, encontré la palabra clave "nueva" que, para mí, "separa" las cosas. Con la nueva palabra clave, crea cosas. Sin la nueva palabra clave, sé que no la confundiré con la creación de cosas a menos que la función que invoca me dé fuertes pistas de eso.

Por ejemplo, con var bar=foo(); No tengo pistas sobre qué barra podría ser ... ¿Es un valor de retorno o es un objeto recién creado? Pero con var bar = new foo(); Sé con certeza que la barra es un objeto.


43
2017-12-22 09:22



Otro caso para nuevo es lo que llamo Pooh Coding. Winnie the Pooh sigue su barriguita. Yo digo ir con el idioma que estás usando, no en contra eso.

Lo más probable es que los mantenedores del idioma optimicen el idioma de los modismos que intentan alentar. Si ponen una nueva palabra clave en el idioma, probablemente piensen que tiene sentido ser claro al crear una nueva instancia.

El código escrito siguiendo las intenciones del idioma aumentará en eficiencia con cada lanzamiento. Y el código que evita las construcciones clave del lenguaje sufrirá con el tiempo.

EDITAR: Y esto va más allá del rendimiento. No puedo contar las veces que escuché (o dije) "¿Por qué demonios lo hicieron? ese? "cuando se busca un código de aspecto extraño. A menudo resulta que en el momento en que se escribió el código había una razón" buena "para ello. Seguir el Tao del idioma es su mejor seguro por no haber ridiculizado su código hace algunos años. ahora.


39
2017-12-20 18:25



Escribí una publicación sobre cómo mitigar el problema de llamar a un constructor sin la nueva palabra clave.
Es principalmente didáctico, pero muestra cómo puedes crear constructores que trabajan con o sin new y no requiere que agregue código repetitivo Probar this en cada constructor

http://js-bits.blogspot.com/2010/08/constructors-without-using-new.html

Aquí está la esencia de la técnica:

/**
 * Wraps the passed in constructor so it works with
 * or without the new keyword
 * @param {Function} realCtor The constructor function.
 *    Note that this is going to be wrapped
 *    and should not be used directly 
 */
function ctor(realCtor){
  // This is going to be the actual constructor
  return function wrapperCtor(){
    var obj; // object that will be created
    if (this instanceof wrapperCtor) {
      // Called with new
      obj = this;
    } else {
      // Called without new. Create an empty object of the
      // correct type without running that constructor
      surrogateCtor.prototype = wrapperCtor.prototype;
      obj = new surrogateCtor();
    }
    // Call the real constructor function
    realCtor.apply(obj, arguments);
    return obj;
  }

  function surrogateCtor() {}
}

He aquí cómo usarlo:

// Create our point constructor
Point = ctor(function(x,y){
  this.x = x;
  this.y = y;
});

// This is good
var pt = new Point(20,30);
// This is OK also
var pt2 = Point(20,30);

24
2018-06-20 22:52



El razonamiento detrás de no usar la nueva palabra clave es simple:

Al no usarlo en absoluto, evita la trampa que viene accidentalmente omitiéndola. El patrón de construcción que YUI usa es un ejemplo de cómo se puede evitar la nueva palabra clave por completo "

var foo = function () {
    var pub= { };
    return pub;
}
var bar = foo();

Alternativamente podrías hacerlo así:

function foo() { }
var bar = new foo();

Pero al hacerlo, corre el riesgo de que alguien se olvide de usar el nuevo palabra clave y el esta el operador es todo fubar. AFAIK no hay ninguna ventaja para hacer esto (aparte de lo que está acostumbrado).

Al final del día: Se trata de estar a la defensiva.  ¿Puedes usar la nueva declaración? Sí. ¿Hace tu código más peligroso? Sí.

Si alguna vez ha escrito C ++, es similar a establecer punteros a NULL después de eliminarlos.


22
2017-12-20 15:42



Creo que "nuevo" agrega claridad al código. Y la claridad vale todo. Es bueno saber que hay trampas, pero evitarlas evitando la claridad no parece ser el camino para mí.


20
2017-12-20 16:12



Caso 1: new no es obligatorio y debe evitarse

var str = new String('asd');  // type: object
var str = String('asd');      // type: string

var num = new Number(12);     // type: object
var num = Number(12);         // type: number

Caso 2 new es obligatorio, de lo contrario recibirá un error

new Date().getFullYear();     // correct, returns the current year, i.e. 2010
Date().getFullYear();         // invalid, returns an error

15
2017-11-13 17:04



Aquí está el resumen más breve que podría hacer de los dos argumentos más fuertes a favor y en contra de usar el new operador:

Argumento en contra new

  1. Funciones diseñadas para ser instanciado como objetos usando el new el operador puede tener un desastroso efectos si son incorrectos invocado como funciones normales. UN el código de la función en tal caso ser ejecutado en el ámbito donde el función se llama, en lugar de en el alcance de un objeto local como destinado a. Esto puede causar global variables y propiedades para obtener sobrescrito con desastroso Consecuencias.
  2. Finalmente, escribiendo function Func(), y luego llamar Func.prototype y agregarle cosas para que puede llamar new Func() para construir su objeto parece feo para algunos programadores, que preferirían usar otro estilo de herencia de objetos para arquitectónico y estilístico razones.

Para más información sobre este argumento, consulte el gran y conciso libro de Douglas Crockford, Javascript: The Good Parts. De hecho, échale un vistazo de todos modos.

Argumento a favor de new

  1. Utilizando el new operador junto con la asignación prototípica es rápida.
  2. Eso de accidentalmente ejecutando una función de constructor el código en el espacio de nombre global puede ser fácilmente prevenido si siempre incluir un poco de código en su funciones del constructor para verificar ver si están siendo llamados correctamente, y, en los casos donde no lo son, manejando la llamada apropiadamente como se desee

Ver Publicación de John Resig para una explicación simple de esta técnica, y para una explicación generalmente más profunda del modelo de herencia que defiende.


12
2017-12-28 23:47



Estoy de acuerdo con Pez y algunos aquí.

Me parece obvio que "nuevo" es la creación de objetos autodescriptivos, donde el patrón de YUI que Greg Dean describe es completamente oscurecido.

La posibilidad de que alguien pueda escribir var bar = foo; o var bar = baz(); donde baz no es un método de creación de objetos parece lejos más peligroso.


9
2017-12-20 17:10