2016-06-29 2 views
12

мне было интересно, если есть отличный способ сделать это:Есть ли JavaScript неопределенное свойство обработки, как в Angular2 шаблоны

if (app && app.object && app.object.foo) { 
    alert(app.object.foo.bar); 
} 

Это очень долго и «уродливый».

Я узнал, что у Angular2 есть что-то действительно замечательное для подобных случаев. Но я думаю, что это только для шаблонов:

<div>{{this?.object?.foo?.bar}}</div> 

Это заставило меня действительно вышли, потому что у меня есть много кода, который выглядит так же, как и в первом примере. Это получается, но я действительно прыгаю, есть что-то более сложное.

+1

Я хотел бы отметить, что если какое-либо из 'app' или' app.object' или 'app.object.foo' не является правдоподобным, как number' 0', это вернет false. – echonax

+1

Просто FYI, то, что вы описываете, является особенностью TypeScript, а не Angular2. Angular2 (необязательно) использует TypeScript, поэтому вы видите эту функцию в документации Angular2. – JayArby

ответ

10

Многие языки имеют эту функциональность, некоторые называют ее safe navigation operator или даже Elvis operator (да ха-ха).

JavaScript не имеет этой функции. Если вы открыты для использования CoffeeScript, вы можете взглянуть на existential operator.

Но, если вы хотите сохранить с JS, вы должны смотреть на lodash.get(), который позволяет вам делать что-то вроде этого:

var object = { 'a': [{ 'b': { 'c': 3 } }] }; 

_.get(object, 'a[0].b.c'); 
// → 3 

_.get(object, 'a.b.d.c', 'default'); 
// → 'default' 
+0

Ох. Так вот как это называется. Был поиск со всеми другими ключевыми словами. Мне нравится этот подход. Думаю, я объединю этот подход с одним из @ nikhil-maheshwari. Передача свойств как одного аргумента - разделение точки (как обычно). благодаря – drinovc

7

Я нашел это решение некоторое время назад на сети:

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/

+0

Это также хороший подход. Это не так аккуратно, как угловатое, но это все еще хорошо. – drinovc

+0

Я действительно был в подобной ситуации и нашел это полезным! –

+0

Мне это нравится, МНОГО. Нет сторонних скриптов или фреймворков; просто чистая функция JS. – MonkeyZeus

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 

Довод заказ таким образом вокруг, так как эта функция обычно кэрри в моем коде, так что я могу do sth like:

arr.map(fetch('some.deeper.path')); 
+0

Это выглядит довольно круто и просто в использовании! – rinukkusu

2

Чуть короче (чем оригинал) способ в 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, он, вероятно, сломал бы его, не добавляя некоторые проверки ввода.