que - javascript pdf
¿Hay un operador de navegación nula(Elvis) o un operador de navegación seguro en javascript? (14)
Explicaré con el ejemplo:
Operador de Elvis (?:)
El "operador de Elvis" es un acortamiento del operador ternario de Java. Una instancia de donde esto es útil es para devolver un valor "predeterminado sensible" si una expresión se resuelve como falsa o nula. Un ejemplo simple podría verse así:
def gender = user.male ? "male" : "female" //traditional ternary operator usage
def displayName = user.name ?: "Anonymous" //more compact Elvis operator
Operador de navegación segura (?.)
El operador Safe Navigation se usa para evitar una NullPointerException. Normalmente, cuando tiene una referencia a un objeto, es posible que necesite verificar que no sea nulo antes de acceder a los métodos o las propiedades del objeto. Para evitar esto, el operador de navegación segura simplemente devolverá nulo en lugar de lanzar una excepción, así:
def user = User.find( "admin" ) //this might be null if ''admin'' does not exist
def streetName = user?.address?.street //streetName will be null if user or user.address is null - no NPE thrown
Actualmente hay un borrador de especificaciones para él:
Aquí hay un simple operador de elvis equivalente:
function elvis(object, path) {
return path ? path.split(''.'').reduce(function (nestedObject, key) {
return nestedObject && nestedObject[key];
}, object) : object;
}
> var o = { a: { b: 2 }, c: 3 };
> elvis(o)
{ a: { b: 2 }, c: 3 }
> elvis(o, ''a'');
{ b: 2 }
> elvis(o, ''a.b'');
2
> elvis(o, ''x'');
undefined
Creo que lo siguiente es equivalente al operador de navegación segura, aunque un poco más:
var streetName = user && user.address && user.address.street;
streetName
será el nombre de la calle o null / undefined.
Si quieres que sea predeterminado para otra cosa, puedes combinarlo con el atajo anterior o para dar:
var streetName = (user && user.address && user.address.street) || "Unknown Street";
Creo que lodash _.get()
puede ayudar aquí, como en _.get(user, ''name'')
, y tareas más complejas como _.get(o, ''a[0].b.c'', ''default-value'')
El operador lógico O de Javascript está short-circuiting y puede reemplazar a su operador "Elvis":
var displayName = user.name || "Anonymous";
Sin embargo, que yo sepa, no hay equivalente a su ?.
operador.
Esta fue una solución interesante para el operador de navegación segura que utilizaba algunos mixin ..
http://jsfiddle.net/avernet/npcmv/
// Assume you have the following data structure
var companies = {
orbeon: {
cfo: "Erik",
cto: "Alex"
}
};
// Extend Underscore.js
_.mixin({
// Safe navigation
attr: function(obj, name) { return obj == null ? obj : obj[name]; },
// So we can chain console.log
log: function(obj) { console.log(obj); }
});
// Shortcut, ''cause I''m lazy
var C = _(companies).chain();
// Simple case: returns Erik
C.attr("orbeon").attr("cfo").log();
// Simple case too, no CEO in Orbeon, returns undefined
C.attr("orbeon").attr("ceo").log();
// IBM unknown, but doesn''t lead to an error, returns undefined
C.attr("ibm").attr("ceo").log();
Esto es más comúnmente conocido como un operador nulo-coalescente. Javascript no tiene uno.
Ocasionalmente, he encontrado el siguiente modismo útil:
a?.b.?c
puede ser reescrito como:
((a||{}).b||{}).c
Esto aprovecha el hecho de que obtener atributos desconocidos en un objeto no es definido, en lugar de arrojar una excepción como lo hace en null
o undefined
, por lo que reemplazamos nulos y sin definir con un objeto vacío antes de navegar.
Para el primero, puedes usar ||
. El operador "lógico o" de Javascript, en lugar de simplemente devolver valores verdaderos y falsos enlatados, sigue la regla de devolver su argumento de la izquierda si es verdadero, y de lo contrario evalúa y devuelve su argumento correcto. Cuando solo te interesa el valor de verdad, funciona igual, pero también significa que foo || bar || baz
foo || bar || baz
foo || bar || baz
devuelve el más a la izquierda de foo, bar o baz que contiene un valor verdadero .
Sin embargo, no encontrará uno que pueda distinguir entre falso y nulo, y 0 y cadena vacía son valores falsos, así que evite usar el value || default
construcción value || default
donde el value
puede ser legítimamente 0 o ""
.
Personalmente uso
function e(e,expr){try{return eval(expr);}catch(e){return null;}};
y por ejemplo, obtener seguro:
var a = e(obj,''e.x.y.z.searchedField'');
Puede lograr aproximadamente el mismo efecto diciendo:
var displayName = user.name || "Anonymous";
Puede usar el operador lógico ''OR'' en lugar del operador de Elvis:
Por ejemplo displayname = user.name || "Anonymous"
displayname = user.name || "Anonymous"
.
Pero Javascript actualmente no tiene la otra funcionalidad. Yo recomendaría mirar CoffeeScript si quieres una sintaxis alternativa. Tiene una forma abreviada que es similar a lo que estás buscando.
Por ejemplo, The Existenntial Operator
zip = lottery.drawWinner?().address?.zipcode
Atajos de funciones
()-> // equivalent to function(){}
Llamada de función atractiva
func ''arg1'',''arg2'' // equivalent to func(''arg1'',''arg2'')
También hay comentarios y clases de líneas múltiples. Obviamente, tiene que compilar esto para javascript o insertar en la página como <script type=''text/coffeescript>''
pero agrega mucha funcionalidad :). Usar <script type=''text/coffeescript''>
realidad solo está destinado al desarrollo y no a la producción.
Tengo una solución para eso, adaptarla a tus propias necesidades, un extracto de una de mis libs:
elvisStructureSeparator: ''.'',
// An Elvis operator replacement. See:
// http://coffeescript.org/ --> The Existential Operator
// http://fantom.org/doc/docLang/Expressions.html#safeInvoke
//
// The fn parameter has a SPECIAL SYNTAX. E.g.
// some.structure[''with a selector like this''].value transforms to
// ''some.structure.with a selector like this.value'' as an fn parameter.
//
// Configurable with tulebox.elvisStructureSeparator.
//
// Usage examples:
// tulebox.elvis(scope, ''arbitrary.path.to.a.function'', fnParamA, fnParamB, fnParamC);
// tulebox.elvis(this, ''currentNode.favicon.filename'');
elvis: function (scope, fn) {
tulebox.dbg(''tulebox.elvis('' + scope + '', '' + fn + '', args...)'');
var implicitMsg = ''....implicit value: undefined '';
if (arguments.length < 2) {
tulebox.dbg(implicitMsg + ''(1)'');
return undefined;
}
// prepare args
var args = [].slice.call(arguments, 2);
if (scope === null || fn === null || scope === undefined || fn === undefined
|| typeof fn !== ''string'') {
tulebox.dbg(implicitMsg + ''(2)'');
return undefined;
}
// check levels
var levels = fn.split(tulebox.elvisStructureSeparator);
if (levels.length < 1) {
tulebox.dbg(implicitMsg + ''(3)'');
return undefined;
}
var lastLevel = scope;
for (var i = 0; i < levels.length; i++) {
if (lastLevel[levels[i]] === undefined) {
tulebox.dbg(implicitMsg + ''(4)'');
return undefined;
}
lastLevel = lastLevel[levels[i]];
}
// real return value
if (typeof lastLevel === ''function'') {
var ret = lastLevel.apply(scope, args);
tulebox.dbg(''....function value: '' + ret);
return ret;
} else {
tulebox.dbg(''....direct value: '' + lastLevel);
return lastLevel;
}
},
Funciona de maravilla. Disfruta el menos dolor!
Usted puede hacer su propio:
function resolve(objectToGetValueFrom, stringOfDotSeparatedParameters) {
var returnObject = objectToGetValueFrom,
parameters = stringOfDotSeparatedParameters.split(''.''),
i,
parameter;
for (i = 0; i < parameters.length; i++) {
parameter = parameters[i];
returnObject = returnObject[parameter];
if (returnObject === undefined) {
return undefined;
}
}
return returnObject;
};
Y la usa así:
var result = resolve(obj, ''a.b.c.d'');
* el resultado no está definido. Cualquiera de a, b, c o d no está definido