En otra pregunta , un usuario señaló que la new
palabra clave era peligrosa de usar y propuso una solución para la creación de objetos que no se usó new
. No creía que eso fuera cierto, principalmente porque he usado Prototype, Scriptaculous y otras excelentes bibliotecas de JavaScript, y todos ellos usaron la 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 ya no usaba la new
palabra clave en su código ( Crockford en JavaScript - Acto III: Function the Ultimate - 50:23 minutos ).
¿Es 'malo' usar la new
palabra clave? ¿Cuáles son las ventajas y desventajas de usarlo?
javascript
Pablo Fernández
fuente
fuente
new
. Pero cuando miras la biblioteca YUI. Tienes que usar ennew
todas partes. Tales comovar myDataSource = new Y.DataSource.IO({source:"./myScript.php"});
.init
método si está utilizando elObject.create
enfoque y llamarlo después. Mucho más fácil de usarnew
que hace ambas cosas, establece la cadena del prototipo y llama a un código inicializador.new
no es peligroso. Omitirnew
es peligroso y, por lo tanto, malo . Pero en ES5 puede usar el modo estricto , que lo protege de ese peligro y de muchos otros.Respuestas:
Crockford ha hecho mucho para popularizar buenas técnicas de JavaScript. Su postura obstinada sobre los elementos clave del lenguaje ha provocado muchas discusiones útiles. Dicho esto, hay demasiadas personas que toman cada proclamación de "malo" o "dañino" como un evangelio, y se niegan a mirar más allá de la opinión de un hombre. Puede ser un poco frustrante a veces.
El uso de la funcionalidad proporcionada por la
new
palabra clave tiene varias ventajas sobre la construcción de cada objeto desde cero:prototype
y usonew
para estampar 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 también evita que cada objeto tenga globos con 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 sí,
new
tiene una desventaja crucial, descrita hábilmente por otras respuestas: si olvida usarlo, su 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í:Ahora puede tener las ventajas de
new
sin tener que preocuparse por los problemas causados por un mal uso accidental. Incluso podría agregar una afirmación al cheque si la idea de que el código roto funcione silenciosamente le molesta. O, como algunos comentaron, use la verificación para introducir una excepción de tiempo de ejecución:(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 del objeto; por lo tanto, se puede copiar en cada función de destino sin modificación).
John Resig entra en detalles sobre esta técnica en su publicación de instanciación de "Clase" Simple , así como también incluye un medio para construir este comportamiento en sus "clases" de forma predeterminada. Definitivamente vale la pena leer ... al igual que su próximo libro, Secretos del JavaScript Ninja , que encuentra el oro oculto en esto y muchos otros "perjudicial" características del lenguaje JavaScript (el capítulo en
with
que se alumbra en especial para aquellos de nosotros que inicialmente rechazó esta característica muy difamada como un truco).fuente
new
, o use una función de contenedor para recordarlo por usted. Yo sospecho que si usted está en el punto donde realmente importa, que haya agotado ya otras optimizaciones tales como memoization, por lo que sus llamadas de creación serán localizados todos modos ...arguments.callee
para verificar si te han llamadonew
puede no ser tan bueno, yaarguments.callee
que no está disponible en modo estricto. Es mejor usar el nombre de la función.new
porque puedes olvidarte de escribirlo en tu código es tan ridículo como mi ejemplo.Acabo de leer algunas partes de su libro de Crockfords "Javascript: The Good Parts". Tengo la sensación de que él considera que todo lo que lo ha mordido es dañino:
Sobre la caída del interruptor:
Acerca de ++ y -
Acerca de nuevo:
Hay más, pero espero que te hagas una idea.
Mi respuesta a su pregunta: No, no es dañino. pero si olvida usarlo cuando debería, podría tener algunos problemas. Si se está desarrollando en un buen entorno, lo nota.
Actualizar
Aproximadamente un año después de que se escribió esta respuesta, se lanzó la quinta edición de ECMAScript, con soporte para el modo estricto . En modo estricto,
this
ya no está vinculado al objeto global sino aundefined
.fuente
Javascript es un lenguaje dinámico, hay muchísimas formas de desordenar donde otro idioma te detendría.
Evitar una característica fundamental del lenguaje, como
new
la posibilidad de que se estropee, es como quitarse los zapatos nuevos y brillantes antes de caminar por un campo minado en caso de que se ensucie los zapatos.Utilizo una convención donde los nombres de funciones comienzan con una letra minúscula y las 'funciones' que en realidad son definiciones de clase comienzan con una letra mayúscula. El resultado es una pista visual realmente convincente de que la 'sintaxis' está mal:
Además de esto, los buenos hábitos de nombres ayudan. Después de que todas las funciones hacen 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.
Es interesante cómo la coloración de sintaxis de SO ha interpretado el código anterior.
fuente
if (! this instanceof MyClass) return new MyClass()
) en realidad prefiero lanew
sintaxis -less. ¿Por qué? Porque las funciones son más genéricas que las funciones de constructor . Dejar de ladonew
hace que sea fácil cambiar una función de constructor a una función regular ... O al revés. Agregarlonew
hace que el código sea más específico de lo que debe ser. Y por lo tanto menos flexible. Compare con Java donde se recomienda aceptar enList
lugar deArrayList
para que la persona que llama pueda elegir la implementación.Soy un novato en Javascript, así que quizás no tengo mucha experiencia en proporcionar un buen punto de vista para esto. Sin embargo, quiero compartir mi punto de vista 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 y el código "nuevos" como el del patrón YUI y no me lleva mucho tiempo encontrar el desastre. Pierdo la noción de lo que se supone que debe hacer una línea en particular cuando miro hacia atrás el código que he escrito. Más caótico es que mi mente realmente no puede transitar entre los límites de instancias de objetos cuando estoy "ejecutando en seco" el código.
Entonces, encontré la palabra clave "nueva" que para mí, "separó" 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 estoy invocando me dé pistas sólidas sobre 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 lo quevar bar = new foo();
estoy seguro, la barra es un objeto.fuente
typeof new foo() == "object"
. Es lo quenew
devuelve una instancia defoo
, y sabes que puedes llamarfoo.bar()
yfoo.bang()
. Sin embargo, eso se puede mitigar fácilmente utilizando @return de JsDoc No es que esté abogando por el código de procedimiento (evitando la palabranew
)Otro caso para lo nuevo es lo que yo llamo Pooh Coding . Winnie the Pooh sigue su barriga. Yo digo ir con el lenguaje que estás usando, no en contra de él.
Lo más probable es que los mantenedores del lenguaje optimicen el lenguaje para 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 lenguaje aumentará en eficiencia con cada versión. Y el código que evita las construcciones clave del lenguaje sufrirá con el tiempo.
EDITAR: Y esto va mucho más allá del rendimiento. No puedo contar las veces que escuché (o dije) "¿por qué demonios hicieron eso ?" al encontrar un código de aspecto extraño. A menudo resulta que en el momento en que se escribió el código había alguna razón "buena" para ello. Seguir el Tao del lenguaje es su mejor seguro para no tener su código ridiculizado en algunos años a partir de ahora.
fuente
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 puede crear constructores que funcionen con o sin ellos
new
y no requiere que agregue código repetitivo para probarthis
en cada constructor.http://js-bits.blogspot.com/2010/08/constructors-without-using-new.html
Aquí está la esencia de la técnica:
Aquí se explica cómo usarlo:
fuente
arguments.callee
es increíble!surrogateConstructor
debería sersurrogateCtor
(o viceversa).La razón detrás de no usar la nueva palabra clave es simple:
Al no usarlo en absoluto, evita la trampa que viene al omitirlo accidentalmente. El patrón de construcción que utiliza YUI es un ejemplo de cómo puede evitar la nueva palabra clave por completo "
Alternativamente, podría hacerlo así:
Pero al hacerlo, corre el riesgo de que alguien se olvide de usar la nueva palabra clave, y este operador sea todo fubar. AFAIK no hay ninguna ventaja en hacer esto (aparte de que estás acostumbrado).
Al final del día: se trata de estar a la defensiva. ¿Puedes usar la nueva declaración? Si. ¿Hace tu código más peligroso? Si.
Si alguna vez ha escrito C ++, es similar a establecer punteros en NULL después de eliminarlos.
fuente
Creo que "nuevo" agrega claridad al código. Y la claridad lo vale todo. Es bueno saber que hay dificultades, pero evitarlas evitando la claridad no parece ser el camino para mí.
fuente
Caso 1:
new
no es obligatorio y debe evitarseCaso 2:
new
es obligatorio; de lo contrario, recibirá un errorfuente
toString()
). En todos los demás casos, use literales. NoString('asd')
, sino simplemente'asd'
, y noNumber(12)
, sino simplemente12
.Array
:Array(5).fill(0)
obviamente es más legible que[undefined, undefined, undefined, undefined, undefined].fill(0)
y(var arr = []).length = 5; arr.fill(0);
new
con constructores para tipos de objetos correspondientes a tipos primitivos . El literal que sugiere no es equivalente a laArray
llamada (intente0 in …
), y el resto es un error de sintaxis :) De lo contrario, es correcto, aunque también debe tenerse en cuenta queArray(5)
puede ser ambiguo si considera implementaciones no conformes (y por lo tanto, un emuladoArray.prototype.fill(…)
).Aquí está el resumen más breve que podría hacer de los dos argumentos más fuertes a favor y en contra del uso del
new
operador:Argumento en contra
new
new
operador pueden tener efectos desastrosos si se invocan incorrectamente como funciones normales. El código de una función en tal caso se ejecutará en el ámbito donde se llama la función, en lugar de en el ámbito de un objeto local como se pretendía. Esto puede hacer que las variables y propiedades globales se sobrescriban con consecuencias desastrosas.function Func()
, y luego llamarFunc.prototype
y agregar cosas para que pueda llamarnew Func()
para construir su objeto parece feo para algunos programadores, que prefieren usar otro estilo de herencia de objetos por razones arquitectónicas y estilísticas.Para obtener más información sobre este argumento, consulte el excelente y conciso libro de Douglas Crockford Javascript: The Good Parts. De hecho, échale un vistazo de todos modos.
Argumento a favor de
new
new
operador junto con la asignación de prototipos es rápido.Vea la 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.
fuente
'use strict';
modo (o el método en su enlace) # 2 Tiene azúcar sincrónico en ES6 , sin embargo, el comportamiento es el mismo que antes.Estoy de acuerdo con pez y algunos aquí.
Me parece obvio que "nuevo" es la creación de objetos autodescriptivos, donde el patrón YUI que describe Greg Dean está completamente oscurecido .
La posibilidad de que alguien pueda escribir
var bar = foo;
ovar bar = baz();
donde baz no es un método de creación de objetos parece mucho más peligroso.fuente
Creo que lo nuevo es malo, no porque si se olvida de usarlo por error puede causar problemas, sino porque arruina la cadena de herencia, haciendo que el lenguaje sea más difícil de entender.
JavaScript está orientado a objetos basado en prototipos. Por lo tanto, cada objeto DEBE ser creado a partir de otro objeto así
var newObj=Object.create(oldObj)
. Aquí oldObj se llama prototipo de newObj (por lo tanto, "basado en prototipos"). Esto implica que si una propiedad no se encuentra en newObj , se buscará en oldObj . newObj por defecto será un objeto vacío, pero debido a su cadena de prototipo parece tener todos los valores de oldObj .Por otro lado, si lo hace
var newObj=new oldObj()
, el prototipo de newObj es oldObj.prototype , que es innecesariamente difícil de entender.El truco es usar
Está dentro de esta función y solo aquí se debe usar new. Después de esto, simplemente use el método Object.create () . El método resuelve el problema del prototipo.
fuente
var c = new Car()
es lo mismo que hacervar c = Object.create(Car.prototype); Car.call(c)