在JavaScript中是否存在null-coalescing(Elvis)运算符或安全导航运算符?

我会通过例子来解释:

猫王操作员(?:)

“Elvis操作符”是Java三元操作符的缩写。 如果expression式parsing为false或null,则返回“合理的默认值”。 一个简单的例子可能是这样的:

def gender = user.male ? "male" : "female" //traditional ternary operator usage def displayName = user.name ?: "Anonymous" //more compact Elvis operator 

安全导航操作员(?)

安全导航运算符用于避免NullPointerException。 通常当你有一个对象的引用时,你可能需要在访问对象的方法或属性之前validation它是否为空。 为了避免这种情况,安全导航操作符将简单地返回null而不是抛出exception,如下所示:

 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 

您可以使用逻辑“OR”运算符代替Elvis运算符:

例如displayname = user.name || "Anonymous" displayname = user.name || "Anonymous"

但是,Javascript目前还没有其他的function。 我build议看看CoffeeScript,如果你想要一个替代的语法。 它有一些速记,类似于你正在寻找的。

例如存在的操作员

 zip = lottery.drawWinner?().address?.zipcode 

function快捷键

 ()-> // equivalent to function(){} 

性感的function调用

 func 'arg1','arg2' // equivalent to func('arg1','arg2') 

还有多行注释和类。 很明显,你必须把这个编译成javascript或者以<script type='text/coffeescript>'插入页面,但是它增加了很多function:)。 使用<script type='text/coffeescript'>实际上仅用于开发而不是生产。

Javascript的逻辑OR运算符是短路的 ,可以代替你的“Elvis”运算符:

 var displayName = user.name || "Anonymous"; 

但是,据我所知,这和你没有什么相同之处?. 运营商。

我认为以下相当于安全的导航操作员,虽然有点长:

 var streetName = user && user.address && user.address.street; 

streetName将会是街道名称或null / undefined。

如果你想默认其他东西,你可以结合上面的快捷方式或给:

 var streetName = (user && user.address && user.address.street) || "Unknown Street"; 

我偶尔会发现以下成语有用:

 a?.b.?c 

可以改写为:

 ((a||{}).b||{}).c 

这利用了这样一个事实,即在对象上获取未知的属性返回未定义的,而不是抛出一个exception,因为它在nullundefined ,因此我们在导航之前用一个空对象replacenull和undefined。

我认为lodash _.get()可以在_.get(user, 'name')和更复杂的任务(如_.get(o, 'a[0].b.c', 'default-value')

对于前者,你可以使用|| 。 Javascript“逻辑”或“运算符”,而不是简单地返回jar头的真值和假值,遵循返回它的左参数的规则,如果它是真的,否则评估和返回它的正确的参数。 当你只对真值感兴趣时,结果是一样的,但也意味着foo || bar || baz foo || bar || baz foo || bar || baz返回包含真实值的foo,bar或baz中最左边的一个

你不会find一个可以区分false的值,但是,0和空string都是false值,所以避免使用value || default value || default构造的value可以合法地为0或""

这通常被称为空合并运算符。 Javascript没有一个。

我有一个解决scheme,根据自己的需要量身定制,从我的一个库中摘录:

  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. Eg // 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; } }, 

奇迹般有效。 享受更less的痛苦!

这里有一个简单的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 displayName = user.name || "Anonymous"; 

你可以推出自己的:

 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; }; 

而使用它就像这样:

 var result = resolve(obj, 'abcd'); 

*结果未定义a,b,c或d中的任何一个未定义

这是一个有趣的解决scheme,使用一些混合安全导航操作..

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(); 

我个人使用

 function e(e,expr){try{return eval(expr);}catch(e){return null;}}; 

例如安全地得到:

 var a = e(obj,'exyzsearchedField'); 
Interesting Posts