Есть ли обработка свойств JavaScript undefined, как в шаблонах Angular2
Мне было интересно, есть ли способ сделать это:
if (app && app.object && app.object.foo) {
alert(app.object.foo.bar);
}
Это действительно длинный и "уродливый".
Я узнал, что Angular2 имеет что-то действительно замечательное для подобных случаев. Но я думаю, что это только для шаблонов:
<div>{{this?.object?.foo?.bar}}</div>
Мне это действительно удалось выйти, потому что у меня много кода, который выглядит как первый пример. Он выполняет свою работу, но я действительно прыгаю, есть что-то более сложное.
Ответы
Ответ 1
Многие языки имеют эту функциональность, некоторые называют ее safe navigation operator
или даже Elvis operator
(да ха-ха).
JavaScript не имеет этой функции. Если вы открыты для использования CoffeeScript
, вы можете взглянуть на экзистенциальный оператор.
Но, если вы хотите сохранить JS, вы должны взглянуть на lodash.get()
, который позволяет вам сделать что-то вроде этого:
var object = { 'a': [{ 'b': { 'c': 3 } }] };
_.get(object, 'a[0].b.c');
// → 3
_.get(object, 'a.b.d.c', 'default');
// → 'default'
Ответ 2
Я нашел это решение когда-нибудь в сети:
function checkNested(obj /*, level1, level2, ... levelN*/) {
var args = Array.prototype.slice.call(arguments, 1);
for (var i = 0; i < args.length; i++) {
if (!obj || !obj.hasOwnProperty(args[i])) {
return false;
}
obj = obj[args[i]];
}
return true;
}
var test = {level1:{level2:{level3:'level3'}} };
checkNested(test, 'level1', 'level2', 'level3'); // true
checkNested(test, 'level1', 'level2', 'foo'); // false
jsFiddle: https://jsfiddle.net/nikdtu/kjsxnunp/
Ответ 3
не из коробки.
var string = function(v){ return v == null? "": String(v) } //because I usually want this behaviour
var fetch = function(path, obj){
path instanceof Array || (path = string(path).split('.'));
for(var i=0, v=obj; i<path.length; v = v[path[i++]])
if(v == null) return void 0;
return v;
}
и ваш код:
if(fetch("object.foo", app)){
alert(app.object.foo.bar);
}
или даже более прямой:
alert( fetch("object.foo.bar", app) );
//will alert undefined, if the path could not be resolved
Аргумент порядка такой, потому что эта функция обычно находится в моем коде, поэтому я могу сделать так:
arr.map(fetch('some.deeper.path'));
Ответ 4
Немного короче (чем оригинальный) способ в JavaScript (менее читаемый)
if ((a = app) && (o = a.object) && (f = o.foo)) {
alert(f.bar);
}
Как я его напишу в CoffeeScript (мой предпочтительный метод)
alert f.bar if f = app?.object?.foo?
Если вы действительно используете Javascript и хотите, чтобы он выглядел чистым, вы могли бы использовать что-то вроде:
function ifExist (name) { // Returns undefined if it doesn't exist
arr = name.split('.');
obj = eval('if (typeof '+(x = arr.splice(0,1)[0])+' !== \'undefined\') '+x);
for (i = 0; i < arr.length; i++) {
if (typeof obj === 'undefined') {
return obj;
}
else {
obj = obj[arr[i]];
}
}
return obj
}
alert(ifExist('app.object.foo.bar'));
Поскольку он использует eval, он может представлять угрозу безопасности, если пользователь генерирует app.object.foo.bar
. Он работает в простых случаях (например, тот, который вы опубликовали выше), но используя что-то вроде app.object['foo'].bar
в нем, вероятно, сломает его, не добавляя некоторые проверки ввода.