javascript中是否有空合并(Elvis)运算符或安全导航运算符?
我将举例说明: 埃尔维斯算子(?) “Elvis运算符”是一个缩写 Java的三元运算符。一个 这个方便的例子是 返回“合理默认”值 如果表达式解析为false或 无效的一个简单的例子可能是这样的 这: 安全导航操作员(?) 使用安全导航操作器 以避免NullPointerException。 通常,当您引用 可能需要验证的对象 它在访问之前不为null 对象的方法或属性。 为了避免这种情况,安全导航 运算符只返回null 而不是抛出异常,比如 因此:javascript中是否有空合并(Elvis)运算符或安全导航运算符?,javascript,jquery,groovy,safe-navigation-operator,Javascript,Jquery,Groovy,Safe Navigation Operator,我将举例说明: 埃尔维斯算子(?) “Elvis运算符”是一个缩写 Java的三元运算符。一个 这个方便的例子是 返回“合理默认”值 如果表达式解析为false或 无效的一个简单的例子可能是这样的 这: 安全导航操作员(?) 使用安全导航操作器 以避免NullPointerException。 通常,当您引用 可能需要验证的对象 它在访问之前不为null 对象的方法或属性。 为了避免这种情况,安全导航 运算符只返回null 而不是抛出异常,比如 因此: 这通常称为空合并运算符。Javascrip
这通常称为空合并运算符。Javascript没有。Javascript是并可以替换“Elvis”操作符:
var displayName = user.name || "Anonymous";
但是,据我所知,没有与您的
?。
运算符等效的运算符。您可以通过以下方式实现大致相同的效果:
var displayName = user.name || "Anonymous";
对于前者,可以使用
|
。Javascript“logical or”操作符不是简单地返回固定的真值和假值,而是遵循以下规则:如果左参数为真,则返回左参数,否则计算并返回右参数。当您只对真值感兴趣时,结果是一样的,但这也意味着foo | | bar | baz
返回包含真值的foo、bar或baz中最左边的一个
但是,您找不到可以区分false和null的值,并且0和空字符串都是false值,因此请避免使用
值| |默认值
结构,其中值可以合法地为0或”
您可以使用逻辑“或”运算符代替Elvis运算符:
var displayName = user.name || "Anonymous";
例如displayname=user.name | |“匿名”
但是Javascript目前没有其他功能。我建议您看看是否需要其他语法。它有一些速记,类似于你正在寻找的
例如存在算子
zip = lottery.drawWinner?().address?.zipcode
功能快捷方式
()-> // equivalent to function(){}
性感函数调用
func 'arg1','arg2' // equivalent to func('arg1','arg2')
还有多行注释和类。显然,您必须将其编译为javascript或作为插入到页面中我有一个解决方案,根据您自己的需要进行定制,摘自我的一个LIB:
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;
}
},
elvisStructureSeparator:',
//Elvis操作员的更换。见:
// http://coffeescript.org/ -->存在算子
// http://fantom.org/doc/docLang/Expressions.html#safeInvoke
//
//fn参数具有特殊语法。例如。
//some.structure['带有如下']这样的选择器。值转换为
//“some.structure.with a selector this.value”作为fn参数。
//
//可配置tulebox.elvisStructureSeparator。
//
//用法示例:
//elvis(作用域,'arbitral.path.to.a.function',fnParamA,fnParamB,fnParamC);
//elvis(这是“currentNode.favicon.filename”);
elvis:功能(范围,fn){
tulebox.dbg('tulebox.elvis('+scope+','+fn+',args…);
var implicitMsg='..隐式值:未定义';
if(arguments.length<2){
tulebox.dbg(隐式msg+'(1');
返回未定义;
}
//准备args
var args=[].slice.call(参数,2);
如果(范围===null | | fn===null | |范围===未定义| | fn==未定义
||typeof fn!=“字符串”){
tulebox.dbg(隐式msg+'(2');
返回未定义;
}
//检查水平
风险值水平=fn.分割(tulebox.elvisStructureSeparator);
if(levels.length<1){
tulebox.dbg(隐式msg+'(3');
返回未定义;
}
var lastLevel=范围;
对于(变量i=0;i
工作起来很有魅力。享受更少的痛苦 您可以自己制作:
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) {
break;
}
}
return returnObject;
};
*如果a、b、c或d中的任何一个未定义,则结果未定义。这里有一个简单的等效elvis运算符:
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
我认为以下内容相当于安全导航操作器,虽然有点长:
var streetName = user && user.address && user.address.street;
streetName
将是user.address.street
或未定义的值
const myVariable = a?.b?.c ?? 'Some other value';
// Evaluates to 'Some other value'
const myVariable2 = null ?? 'Some other value';
// Evaluates to ''
const myVariable3 = '' ?? 'Some other value';
如果希望它默认为其他内容,可以与上述快捷方式结合使用,或提供:
var streetName = (user && user.address && user.address.street) || "Unknown Street";
我认为lodash在这里会有所帮助,比如在.get(user,'name')
和更复杂的任务中,比如.get(o,'a[0].b.c','default value')
我偶尔发现以下习惯用法很有用:
a?.b?.c
可以重写为:
((a||{}).b||{}).c
这利用了一个事实,即获取对象上的未知属性会返回undefined,而不是像在null
或undefined
上那样抛出异常,因此,在导航之前,我们将null和undefined替换为空对象。对于安全导航操作员来说,这是一个有趣的解决方案,它使用了一些mixin
我个人使用
function e(e,expr){try{return eval(expr);}catch(e){return null;}};
例如,安全获取:
var a = e(obj,'e.x.y.z.searchedField');
目前有一个规范草案:
不过现在,我喜欢使用or
更新(截至2019年12月23日):
可选链接已移至第4阶段
我阅读了本文()并使用代理修改了解决方案
function safe(obj) {
return new Proxy(obj, {
get: function(target, name) {
const result = target[name];
if (!!result) {
return (result instanceof Object)? safe(result) : result;
}
return safe.nullObj;
},
});
}
safe.nullObj = safe({});
safe.safeGet= function(obj, expression) {
let safeObj = safe(obj);
let safeResult = expression(safeObj);
if (safeResult === safe.nullObj) {
return undefined;
}
return safeResult;
}
var a = e(obj,'e.x.y.z.searchedField');
function safe(obj) {
return new Proxy(obj, {
get: function(target, name) {
const result = target[name];
if (!!result) {
return (result instanceof Object)? safe(result) : result;
}
return safe.nullObj;
},
});
}
safe.nullObj = safe({});
safe.safeGet= function(obj, expression) {
let safeObj = safe(obj);
let safeResult = expression(safeObj);
if (safeResult === safe.nullObj) {
return undefined;
}
return safeResult;
}
safe.safeGet(example, (x) => x.foo.woo)
Object.prototype.getSafe = function (expression) {
return safe.safeGet(this, expression);
};
example.getSafe((x) => x.foo.woo);
// this will create the object/array if null
Object.prototype.__ = function (prop) {
if (this[prop] === undefined)
this[prop] = typeof prop == 'number' ? [] : {}
return this[prop]
};
// this will just check if object/array is null
Object.prototype._ = function (prop) {
return this[prop] === undefined ? {} : this[prop]
};
let student = {
classes: [
'math',
'whatev'
],
scores: {
math: 9,
whatev: 20
},
loans: [
200,
{ 'hey': 'sup' },
500,
300,
8000,
3000000
]
}
// use one underscore to test
console.log(student._('classes')._(0)) // math
console.log(student._('classes')._(3)) // {}
console.log(student._('sports')._(3)._('injuries')) // {}
console.log(student._('scores')._('whatev')) // 20
console.log(student._('blabla')._('whatev')) // {}
console.log(student._('loans')._(2)) // 500
console.log(student._('loans')._(1)._('hey')) // sup
console.log(student._('loans')._(6)._('hey')) // {}
// use two underscores to create if null
student.__('loans').__(6)['test'] = 'whatev'
console.log(student.__('loans').__(6).__('test')) // whatev
// `undefined` if either `a` or `b` are `null`/`undefined`. `a.b.c` otherwise.
const myVariable = a?.b?.c;
const myVariable = a && a.b && a.b.c;
const myVariable = a?.b?.c ?? 'Some other value';
// Evaluates to 'Some other value'
const myVariable2 = null ?? 'Some other value';
// Evaluates to ''
const myVariable3 = '' ?? 'Some other value';
const myVariable = a?.b?.c || 'Some other value';
// Evaluates to 'Some other value'
const myVariable2 = null || 'Some other value';
// Evaluates to 'Some other value'
const myVariable3 = '' || 'Some other value';