with while funcion for estructura ejercicios ejemplos check javascript language-features with-statement

while - typeof date javascript



¿Hay usos legítimos para la declaración "with" de JavaScript? (30)

Apenas vale la pena ya que puedes hacer lo siguiente:

var o = incrediblyLongObjectNameThatNoOneWouldUse; o.name = "Bob"; o.age = "50";

Los comentarios de Alan Storm en respuesta a mi respuesta con respecto a la declaración me hicieron pensar. Rara vez he encontrado una razón para usar esta característica de lenguaje en particular, y nunca había pensado mucho en cómo podría causar problemas. Ahora, tengo curiosidad por saber cómo podría hacer un uso efectivo de, mientras evito sus trampas.

¿Dónde has encontrado la declaración with útil?


Como indicaron mis comentarios anteriores, no creo que pueda usar with seguridad sin importar cuán tentador pueda ser en cualquier situación. Como el tema no se trata directamente aquí, lo repetiré. Considere el siguiente código

user = {}; someFunctionThatDoesStuffToUser(user); someOtherFunction(user); with(user){ name = ''Bob''; age = 20; }

Sin investigar cuidadosamente esas llamadas de función, no hay forma de saber cuál será el estado de su programa después de que se ejecute este código. Si user.name ya estaba configurado, ahora será Bob . Si no se estableció, el name global se inicializará o cambiará a Bob y el objeto de user permanecerá sin una propiedad de name .

Los errores suceden. Si usa con usted, eventualmente hará esto y aumentará las posibilidades de que su programa falle. Peor aún, es posible que encuentre un código de trabajo que establece un carácter global en el bloque with, ya sea deliberadamente o por medio del autor que no conoce esta peculiaridad de la construcción. Es muy parecido a encontrarse con un interruptor, no tienes idea si el autor lo intentó y no hay manera de saber si "arreglar" el código introducirá una regresión.

Los lenguajes de programación modernos están repletos de características. Algunas características, después de años de uso, se descubren como malas y deben evitarse. Javascript es uno de ellos.


Creé una función de "fusión" que elimina parte de esta ambigüedad con la declaración with :

if (typeof Object.merge !== ''function'') { Object.merge = function (o1, o2) { // Function to merge all of the properties from one object into another for(var i in o2) { o1[i] = o2[i]; } return o1; }; }

Puedo usarlo de forma similar a with , pero puedo saber que no afectará a ningún ámbito que no pretendo que afecte.

Uso:

var eDiv = document.createElement("div"); var eHeader = Object.merge(eDiv.cloneNode(false), {className: "header", onclick: function(){ alert("Click!"); }}); function NewObj() { Object.merge(this, {size: 4096, initDate: new Date()}); }


Creo que el uso del objeto literal es interesante, como un reemplazo directo para usar un cierre

for(var i = nodes.length; i--;) { // info is namespaced in a closure the click handler can access! (function(info) { nodes[i].onclick = function(){ showStuff(info) }; })(data[i]); }

o con la declaración equivalente de un cierre

for(var i = nodes.length; i--;) { // info is namespaced in a closure the click handler can access! with({info: data[i]}) { nodes[i].onclick = function(){ showStuff(info) }; } }

Creo que el riesgo real es la minipulación accidental de variables que no forman parte de la declaración with, por lo que me gusta el objeto literal al que se pasa, puedes ver exactamente lo que estará en el contexto agregado en el código.


Creo que el uso obvio es como atajo. Si, por ejemplo, está inicializando un objeto, simplemente guarde escribiendo "ObjectName". Algo así como "with-slots" de lisp que te permite escribir

(with-slots (foo bar) objectname "some code that accesses foo and bar"

que es lo mismo que escribir

"some code that accesses (slot-value objectname ''foo) and (slot-value objectname ''bar)""

Es más obvio por qué esto es un atajo cuando su idioma permite "Objectname.foo" pero aún así.


Creo que el with-statement puede ser útil al convertir un lenguaje de plantilla a JavaScript. Por ejemplo JST en base2 , pero lo he visto más a menudo.

Estoy de acuerdo en que uno puede programar esto sin el with-statement. Pero porque no da ningún problema es un uso legítimo.


De hecho, encontré que la declaración with es increíblemente útil recientemente. Esta técnica nunca se me ocurrió hasta que comencé mi proyecto actual, una consola de línea de comandos escrita en JavaScript. Estaba intentando emular las API de la consola de Firebug / WebKit, donde se pueden ingresar comandos especiales en la consola, pero no anulan ninguna variable en el ámbito global. Pensé en esto cuando intentaba superar un problema que mencioné en los comentarios a la excelente respuesta de Shog9 .

Para lograr este efecto, usé dos con declaraciones para "estrechar" un alcance detrás del alcance global:

with (consoleCommands) { with (window) { eval(expression); } }

Lo mejor de esta técnica es que, aparte de las desventajas de rendimiento, no sufre los temores habituales de la declaración with porque, de todos modos, estamos evaluando en el ámbito global. No hay peligro de que existan variables fuera de nuestro pseudo-alcance. siendo modificado.

Me inspiró para publicar esta respuesta cuando, para mi sorpresa, logré encontrar la misma técnica utilizada en otros lugares: ¡el código fuente de Chromium !

InjectedScript._evaluateOn = function(evalFunction, object, expression) { InjectedScript._ensureCommandLineAPIInstalled(); // Surround the expression in with statements to inject our command line API so that // the window object properties still take more precedent than our API functions. expression = "with (window._inspectorCommandLineAPI) { with (window) { " + expression + " } }"; return evalFunction.call(object, expression); }

EDITAR: Solo revisé la fuente de Firebug, encadenaron 4 con declaraciones para obtener aún más capas. ¡Loco!

const evalScript = "with (__win__.__scope__.vars) { with (__win__.__scope__.api) { with (__win__.__scope__.userVars) { with (__win__) {" + "try {" + "__win__.__scope__.callback(eval(__win__.__scope__.expr));" + "} catch (exc) {" + "__win__.__scope__.callback(exc, true);" + "}" + "}}}}";


He estado usando la instrucción with como una forma simple de importación de ámbito. Digamos que usted tiene un generador de marcado de algún tipo. En lugar de escribir:

markupbuilder.div( markupbuilder.p(''Hi! I am a paragraph!'', markupbuilder.span(''I am a span inside a paragraph'') ) )

En su lugar, podrías escribir:

with(markupbuilder){ div( p(''Hi! I am a paragraph!'', span(''I am a span inside a paragraph'') ) ) }

Para este caso de uso, no estoy haciendo ninguna tarea, así que no tengo el problema de ambigüedad asociado con eso.


Hoy se me ocurrió otro uso, así que busqué en la web con entusiasmo y encontré una mención existente: Definición de variables dentro del ámbito del bloque .

Fondo

JavaScript, a pesar de su parecido superficial con C y C ++, no abarca variables al bloque en el que se definen:

var name = "Joe"; if ( true ) { var name = "Jack"; } // name now contains "Jack"

Declarar un cierre en un bucle es una tarea común donde esto puede llevar a errores:

for (var i=0; i<3; ++i) { var num = i; setTimeout(function() { alert(num); }, 10); }

Debido a que el bucle for no introduce un nuevo alcance, las tres funciones compartirán el mismo num , con un valor de 2 .

Un nuevo ámbito: let y with

Con la introducción de la declaración let en ES6 , resulta fácil introducir un nuevo ámbito cuando sea necesario para evitar estos problemas:

// variables introduced in this statement // are scoped to each iteration of the loop for (let i=0; i<3; ++i) { setTimeout(function() { alert(i); }, 10); }

O incluso:

for (var i=0; i<3; ++i) { // variables introduced in this statement // are scoped to the block containing it. let num = i; setTimeout(function() { alert(num); }, 10); }

Hasta que ES6 esté disponible universalmente, este uso se limita a los navegadores y desarrolladores más nuevos que estén dispuestos a usar transpilers. Sin embargo, podemos simular este comportamiento fácilmente utilizando:

for (var i=0; i<3; ++i) { // object members introduced in this statement // are scoped to the block following it. with ({num: i}) { setTimeout(function() { alert(num); }, 10); } }

El bucle ahora funciona según lo previsto, creando tres variables separadas con valores de 0 a 2. Tenga en cuenta que las variables declaradas dentro del bloque no están sujetas a él, a diferencia del comportamiento de los bloques en C ++ (en C, las variables deben declararse al comienzo de un bloque, por lo que en cierto modo es similar). Este comportamiento es en realidad bastante similar a una sintaxis de bloqueo de let introducida en versiones anteriores de los navegadores Mozilla, pero no ampliamente adoptada en otros lugares.


La instrucción with se puede usar para disminuir el tamaño del código o para miembros de clases privadas, por ejemplo:

// demo class framework var Class= function(name, o) { var c=function(){}; if( o.hasOwnProperty("constructor") ) { c= o.constructor; } delete o["constructor"]; delete o["prototype"]; c.prototype= {}; for( var k in o ) c.prototype[k]= o[k]; c.scope= Class.scope; c.scope.Class= c; c.Name= name; return c; } Class.newScope= function() { Class.scope= {}; Class.scope.Scope= Class.scope; return Class.scope; } // create a new class with( Class.newScope() ) { window.Foo= Class("Foo",{ test: function() { alert( Class.Name ); } }); } (new Foo()).test();

El with-statement es muy útil si desea modificar el alcance, lo que es necesario para tener su propio alcance global que pueda manipular en tiempo de ejecución. Puede poner constantes en él o ciertas funciones de ayuda que se usan a menudo como, por ejemplo, "toUpper", "toLower" o "isNumber", "clipNumber" aso ..

Sobre el mal desempeño lo leo con frecuencia: el alcance de una función no tendrá ningún impacto en el rendimiento, de hecho, en mi FF una función de alcance se ejecuta más rápido que un sin alcance:

var o={x: 5},r, fnRAW= function(a,b){ return a*b; }, fnScoped, s, e, i; with( o ) { fnScoped= function(a,b){ return a*b; }; } s= Date.now(); r= 0; for( i=0; i < 1000000; i++ ) { r+= fnRAW(i,i); } e= Date.now(); console.log( (e-s)+"ms" ); s= Date.now(); r= 0; for( i=0; i < 1000000; i++ ) { r+= fnScoped(i,i); } e= Date.now(); console.log( (e-s)+"ms" );

Por lo tanto, de la manera mencionada anteriormente, el uso de with-statement no tiene un efecto negativo en el rendimiento, pero es bueno ya que disminuye el tamaño del código, lo que afecta el uso de memoria en los dispositivos móviles.


No se recomienda usar con, y está prohibido en el modo estricto ECMAScript 5. La alternativa recomendada es asignar el objeto cuyas propiedades desea acceder a una variable temporal.

Fuente: Mozilla.org


Nunca uso con, no veo una razón para hacerlo, y no lo recomiendo.

El problema es que previene numerosas optimizaciones léxicas que puede realizar una implementación de ECMAScript. Dado el auge de los rápidos motores basados ​​en JIT, este problema probablemente será aún más importante en el futuro cercano.

Puede parecer que with permite construcciones más limpias (cuando, por ejemplo, introducir un nuevo ámbito en lugar de una envoltura de función anónima común o reemplazar un alias detallado), pero realmente no vale la pena . Además de una disminución en el rendimiento, siempre existe el peligro de asignar una propiedad de un objeto incorrecto (cuando la propiedad no se encuentra en un objeto en el ámbito inyectado) y tal vez introducir variables globales por error. IIRC, este último tema es el que motivó a Crockford a recomendar evitar.


Puede definir una pequeña función auxiliar para proporcionar los beneficios de sin la ambigüedad:

var with_ = function (obj, func) { func (obj); }; with_ (object_name_here, function (_) { _.a = "foo"; _.b = "bar"; });


Puede usar with para introducir el contenido de un objeto como variables locales en un bloque, como se hace con este motor de plantilla pequeña .


Sí, sí y sí. Hay un uso muy legítimo. Reloj:

with (document.getElementById("blah").style) { background = "black"; color = "blue"; border = "1px solid green"; }

Básicamente, cualquier otro enganche DOM o CSS son usos fantásticos de con. No es como si "CloneNode" estuviera indefinido y volviera al ámbito global a menos que se saliera de su camino y decidiera hacerlo posible.

La queja de velocidad de Crockford es que un nuevo contexto se crea con. Los contextos son generalmente caros. Estoy de acuerdo. Pero si acaba de crear un div y no tiene un marco para configurar su css y necesita configurar 15 o más propiedades de CSS a mano, entonces crear un contexto probablemente será más barato que la creación de variables y 15 desreferencias:

var element = document.createElement("div"), elementStyle = element.style; elementStyle.fontWeight = "bold"; elementStyle.fontSize = "1.5em"; elementStyle.color = "#55d"; elementStyle.marginLeft = "2px";

etc ...


Teniendo experiencia con Delphi, diría que usar con debe ser una optimización de tamaño de último recurso, posiblemente realizada por algún tipo de algoritmo minimizador de javascript con acceso al análisis de código estático para verificar su seguridad.

Los problemas de alcance que puede obtener con el uso liberal de la sentencia with puede ser un dolor real en la a ** y no me gustaría que nadie experimentara una sesión de depuración para averiguar qué está pasando en su código. , solo para descubrir que capturó un miembro objeto o la variable local incorrecta, en lugar de su variable de alcance global o externa que pretendía.

El VB con la declaración es mejor, ya que necesita los puntos para desambiguar el alcance, pero el Delphi con la declaración es un arma cargada con un hairtrigger, y me parece que el javascript es lo suficientemente similar para justificar la misma advertencia.


Usar "con" puede hacer que su código sea más seco.

Considere el siguiente código:

var photo = document.getElementById(''photo''); photo.style.position = ''absolute''; photo.style.left = ''10px''; photo.style.top = ''10px'';

Puedes secarlo a lo siguiente:

with(document.getElementById(''photo'').style) { position = ''absolute''; left = ''10px''; top = ''10px''; }

Supongo que depende de si tienes preferencia por la legibilidad o la expresividad.

El primer ejemplo es más legible y probablemente se recomienda para la mayoría de los códigos. Pero la mayoría de los códigos son bastante mansos de todos modos. El segundo es un poco más oscuro pero utiliza la naturaleza expresiva del lenguaje para reducir el tamaño del código y las variables superfluas.

Me imagino que las personas a las que les gusta Java o C # elegirían la primera forma (object.member) y las que prefieren Ruby o Python elegirían la última.


Usar con también hace que su código sea más lento en muchas implementaciones, ya que ahora todo está envuelto en un ámbito de búsqueda adicional. No hay ninguna razón legítima para usar con JavaScript.


Visual Basic.NET tiene una instrucción With similar. Una de las formas más comunes en que lo uso es establecer rápidamente una serie de propiedades. En lugar de:

someObject.Foo = '''' someObject.Bar = '''' someObject.Baz = ''''

, Puedo escribir:

With someObject .Foo = '''' .Bar = '''' .Baz = '''' End With

Esto no es sólo una cuestión de pereza. También hace que el código sea mucho más legible. Y a diferencia de JavaScript, no sufre de ambigüedad, ya que tiene que prefijar todo lo afectado por la declaración con un . (punto). Por lo tanto, los dos siguientes son claramente distintos:

With someObject .Foo = '''' End With

contra

With someObject Foo = '''' End With

El primero es someObject.Foo ; el último es Foo en el ámbito fuera de someObject .

Me parece que la falta de distinción de JavaScript hace que sea mucho menos útil que la variante de Visual Basic, ya que el riesgo de ambigüedad es demasiado alto. Aparte de eso, sigue siendo una idea poderosa que puede mejorar la legibilidad.


Es bueno para poner código que se ejecuta en un entorno relativamente complicado en un contenedor: lo uso para hacer un enlace local para "ventana" y para ejecutar código destinado a un navegador web.


Mi

switch(e.type) { case gapi.drive.realtime.ErrorType.TOKEN_REFRESH_REQUIRED: blah case gapi.drive.realtime.ErrorType.CLIENT_ERROR: blah case gapi.drive.realtime.ErrorType.NOT_FOUND: blah }

se reduce a

with(gapi.drive.realtime.ErrorType) {switch(e.type) { case TOKEN_REFRESH_REQUIRED: blah case CLIENT_ERROR: blah case NOT_FOUND: blah }}

¿Se puede confiar en un código de tan baja calidad? No, vemos que se hizo absolutamente ilegible. Este ejemplo prueba sin lugar a dudas que no hay necesidad de una declaración con, si estoy tomando la lectura correcta;)


Puede usar con para evitar tener que gestionar explícitamente la aridad al usar require.js:

var modules = requirejs.declare([{ ''App'' : ''app/app'' }]); require(modules.paths(), function() { with (modules.resolve(arguments)) { App.run(); }});

Implementación de requirejs.declare:

requirejs.declare = function(dependencyPairs) { var pair; var dependencyKeys = []; var dependencyValues = []; for (var i=0, n=dependencyPairs.length; i<n; i++) { pair = dependencyPairs[i]; for (var key in dependencyPairs[i]) { dependencyKeys.push(key); dependencyValues.push(pair[key]); break; } }; return { paths : function() { return dependencyValues; }, resolve : function(args) { var modules = {}; for (var i=0, n=args.length; i<n; i++) { modules[dependencyKeys[i]] = args[i]; } return modules; } } }


Como Andy E señaló en los comentarios de la respuesta de Shog9, este comportamiento potencialmente inesperado ocurre cuando se usa withcon un objeto literal:

for (var i = 0; i < 3; i++) { function toString() { return ''a''; } with ({num: i}) { setTimeout(function() { console.log(num); }, 10); console.log(toString()); // prints "[object Object]" } }

No es que el comportamiento inesperado no fuera ya un sello distintivo de with.

Si realmente desea utilizar esta técnica, al menos use un objeto con un prototipo nulo.

function scope(o) { var ret = Object.create(null); if (typeof o !== ''object'') return ret; Object.keys(o).forEach(function (key) { ret[key] = o[key]; }); return ret; } for (var i = 0; i < 3; i++) { function toString() { return ''a''; } with (scope({num: i})) { setTimeout(function() { console.log(num); }, 10); console.log(toString()); // prints "a" } }

Pero esto solo funcionará en ES5 +. Tampoco lo uses with.


Creo que la utilidad de withpuede depender de qué tan bien esté escrito su código. Por ejemplo, si estás escribiendo un código que aparece así:

var sHeader = object.data.header.toString(); var sContent = object.data.content.toString(); var sFooter = object.data.footer.toString();

entonces podría argumentar que withmejorará la legibilidad del código al hacer esto:

var sHeader = null, sContent = null, sFooter = null; with(object.data) { sHeader = header.toString(); sContent = content.toString(); sFooter = content.toString(); }

A la inversa, podría argumentarse que estás violando la Ley de Deméter , pero, de nuevo, tal vez no. Estoy divagando =).

Por encima de todo, sepa que Douglas Crockford recomienda no usar with. Les insto a que consulten la publicación de su blog withy sus alternativas yuiblog.com/blog/2006/04/11/with-statement-considered-harmful .


Este es un buen uso para with: agregar nuevos elementos a un Objeto Literal, basado en valores almacenados en ese Objeto. Aquí hay un ejemplo que acabo de usar hoy:

Tenía un conjunto de posibles azulejos (con aberturas orientadas hacia arriba, abajo, izquierda o derecha) que se podían usar, y quería una forma rápida de agregar una lista de azulejos que siempre se colocarían y bloquearían al comienzo del juego . No quería seguir escribiendo types.tbrpara cada tipo en la lista, por lo que acabo de usar with.

Tile.types = (function(t,l,b,r) { function j(a) { return a.join('' ''); } // all possible types var types = { br: j( [b,r]), lbr: j([l,b,r]), lb: j([l,b] ), tbr: j([t,b,r]), tbl: j([t,b,l]), tlr: j([t,l,r]), tr: j([t,r] ), tl: j([t,l] ), locked: [] }; // store starting (base/locked) tiles in types.locked with( types ) { locked = [ br, lbr, lbr, lb, tbr, tbr, lbr, tbl, tbr, tlr, tbl, tbl, tr, tlr, tlr, tl ] } return types; })("top","left","bottom","right");


Estoy trabajando en un proyecto que permitirá a los usuarios cargar código para modificar el comportamiento de partes de la aplicación. En este escenario, he estado usando una withcláusula para evitar que su código modifique cualquier cosa fuera del ámbito con el que quiero que jueguen. La parte (simplificada) del código que utilizo para hacer esto es:

// this code is only executed once var localScope = { build: undefined, // this is where all of the values I want to hide go; the list is rather long window: undefined, console: undefined, ... }; with(localScope) { build = function(userCode) { eval(''var builtFunction = function(options) {'' + userCode + ''}''); return builtFunction; } } var build = localScope.build; delete localScope.build; // this is how I use the build method var userCode = ''return "Hello, World!";''; var userFunction = build(userCode);

Este código garantiza (en cierta medida) que el código definido por el usuario no tiene acceso a ningún objeto de ámbito global, como windowtampoco a ninguna de mis variables locales a través de un cierre.

Solo como una palabra para el sabio, todavía tengo que realizar verificaciones de código estático en el código enviado por el usuario para asegurarme de que no estén usando otras maneras astutas para acceder al alcance global. Por ejemplo, el siguiente código definido por el usuario toma acceso directo a window:

test = function() { return this.window }; return test();


La bifurcación de Coco de CoffeeScript tiene una withpalabra clave, pero simplemente se establece this(también puede escribirse como @en CoffeeScript / Coco) para el objeto de destino dentro del bloque. Esto elimina la ambigüedad y logra el cumplimiento estricto del modo ES5:

with long.object.reference @a = ''foo'' bar = @b


Para algunas piezas de código corto, me gustaría usar las funciones trigonométricas como sin, cosetc. en modo grado en lugar de en modo radiante. Para este propósito, uso un AngularDegreeobjeto:

AngularDegree = new function() { this.CONV = Math.PI / 180; this.sin = function(x) { return Math.sin( x * this.CONV ) }; this.cos = function(x) { return Math.cos( x * this.CONV ) }; this.tan = function(x) { return Math.tan( x * this.CONV ) }; this.asin = function(x) { return Math.asin( x ) / this.CONV }; this.acos = function(x) { return Math.acos( x ) / this.CONV }; this.atan = function(x) { return Math.atan( x ) / this.CONV }; this.atan2 = function(x,y) { return Math.atan2(x,y) / this.CONV }; };

Luego puedo usar las funciones trigonométricas en modo grado sin más ruido de lenguaje en un withbloque:

function getAzimut(pol,pos) { ... var d = pos.lon - pol.lon; with(AngularDegree) { var z = atan2( sin(d), cos(pol.lat)*tan(pos.lat) - sin(pol.lat)*cos(d) ); return z; } }

Esto significa: uso un objeto como una colección de funciones, que habilito en una región de código limitado para el acceso directo. Encuentro esto útil.


Realmente no veo cómo usar the with es más legible que solo escribir object.member. No creo que sea menos legible, pero tampoco creo que sea más legible.

Como dijo lassevk, definitivamente puedo ver cómo usar con sería más propenso a errores que simplemente usando la sintaxis muy explícita "object.member".


Tienes que ver la validación de un formulario en javascript en W3schools http://www.w3schools.com/js/js_form_validation.asp donde se "escanea" el formulario del objeto para encontrar una entrada con el nombre ''correo electrónico''

Pero lo modifiqué para obtener de CUALQUIER formulario todos los campos validados como no vacíos, independientemente del nombre o la cantidad de campo en un formulario. Bueno, he probado sólo los campos de texto.

Pero el with () hizo las cosas más simples. Aquí está el código:

function validate_required(field) { with (field) { if (value==null||value=="") { alert(''All fields are mandtory'');return false; } else { return true; } } } function validate_form(thisform) { with (thisform) { for(fiie in elements){ if (validate_required(elements[fiie])==false){ elements[fiie].focus(); elements[fiie].style.border=''1px solid red''; return false; } else {elements[fiie].style.border=''1px solid #7F9DB9'';} } } return false; }