2

私はコードベースを見ていましたが、残念ながら次のようなコードがたくさんありました。

if (module && module.foo && module.foo.bar && module.foo.bar.baz)

これを許容できるようにするlibまたは何かがあるかどうかを確認するためにグーグルを開始しました。見つかりませんでしたが、まだどこかに存在していると確信しています)。私はこれを手短に書きましたが、ルート オブジェクトと '.' で分割する文字列を渡すのは見苦しいので、ちょっと嫌いです。もっと良いものを望んでいました:

<!DOCTYPE html>
<html>
<head>
   <title>safe tests</title>
   <script type="text/javascript">
       function assert(condition, desc) {
           var d = document, li = d.createElement("li");
           li.className = condition ? "pass" : "fail";
           li.appendChild(d.createTextNode(desc));
           d.getElementById('results').appendChild(li);
       }
   </script>
   <style type="text/css">
       #results li.pass { color: green; }
       #results li.fail{ color: red; }
   </style>
</head>
<body>
<ul id="results"></ul>
<script type="text/javascript">
function safe(root, s) {
    var split = s.split('.'), checked = root;
    for (var i = 0, len = split.length; i < len; i++) {
        if (checked[split[i]]) {
           checked = checked[split[i]];
           continue;
        } else {
           return false;
        }
    }
    return true;
}
var foo = {
    bar: {
        baz: {
            qux: 'yippie!'
        }
    }
}
assert(safe(foo, 'bar'), "finds first sub object");
assert(safe(foo, 'bar.baz'), "finds first and then second sub object");
assert(safe(foo, 'bar.baz.qux'), "finds first, second, third, sub object");
assert(!safe(foo, 'bar.baz.qux.NOT'), "rejects if not defined (end)");
assert(!safe(foo, 'NOPE.baz.qux.NOT'), "rejects if not defined (front)");
assert(!safe(foo, 'bar.NO.baz'), "rejects if not defined (middle)");
</script>
</body>
</html>

これをすでに処理している無駄のない提案やライブラリはありますか?

4

4 に答える 4

4
function safe(str, O){
    var seg= str.split('.');
    O= O || window;
    while(O && seg.length) O= O[seg.shift()];
    return O;
}

コードと同じアイデアで、ロードが必要なコードモジュールを見つけるのに最も役立ちます。

于 2013-03-14T03:18:12.570 に答える
2

私は方法だと思います:

if (module && module.foo && module.foo.bar && module.foo.bar.baz)

オブジェクト内の有効なパスをテストするには、依然として最適です。そうは言っても、そのようなものを使用して有効なオブジェクトパスをテストできると思います:

var safeObjectPath = function safeObjectPath( object, properties ) {
    var path = [],
        root = object,
        prop;

    if ( !root ) {
        // if the root object is null we immediately returns
        return false;
    }

    if ( typeof properties === 'string' ) {
        // if a string such as 'foo.bar.baz' is passed,
        // first we convert it into an array of property names
        path = properties ? properties.split('.') : [];
    } else {
        if ( Object.prototype.toString.call( properties ) === '[object Array]' ) {
            // if an array is passed, we don't need to do anything but
            // to assign it to the internal array
            path = properties;
        } else {
            if ( properties ) {
                // if not a string or an array is passed, and the parameter
                // is not null or undefined, we return with false
                return false;
            }
        }
    }

    // if the path is valid or empty we return with true (because the
    // root object is itself a valid path); otherwise false is returned.
    while ( prop = path.shift() ) {
        // Before it was used an if..else statement only, but it
        // could generate an exception in case of inexistent
        // object member. We can fix it using a try..catch
        // statement. Thanks to @xecute for the contribution!
        try {
            if ( prop in root ) {
                root = root[prop];
            } else {
                return false;
            }
        } catch(e) {
            return false;
        }
    }

    return true;
} 

この関数は、文字列または配列を値として受け入れpropertiesます。内部的に、パラメーターは配列に変換され、パスについてテストされます。

プロパティは'foo.bar.baz'またはとして指定できます['foo','bar','baz']

有効なパスをテストするには:

safeObjectPath( module )
safeObjectPath( module, 'foo.bar.baz' )
safeObjectPath( module, [ 'foo', 'bar', 'baz' ] )

最初の形式 (パラメーターのないもの) は有効なパス (ルート) であるため、(渡されたルート オブジェクトが有効な場合はもちろん)propertiesを返すことに注意してください。truemodule

この動作中のfiddleでテストすることは可能です。


再帰的および/またはバインド可能なバージョンも考えられると思います。

編集: Coderwall で公開された私の記事で、より詳細な分析を行ってこの回答を拡張しました。

これは@xecuteによって作成されたパフォーマンス テストです(ご尽力いただきありがとうございます)。

于 2013-03-14T02:01:02.837 に答える
1

このスニペットに出くわしましたか (ここで参照)?

/*decend through an object tree to a specified node, and return it.
If node is unreachable, return undefined. This should also work with arrays in the tree.                                                                                               
Examples:                                                                                                                                                                            
  var test1 = {a:{b:{c:{d:1}}}};                                                                                                                                            
  console.log(objectDesend(test1, 'a', 'b', 'c', 'd'));                                                                                                                
  var test2 = {a:{b:{c:1}}};     //will fail to reach d                                                                                                                                         
  console.log(objectDesend(test2, 'a', 'b', 'c', 'd'));
*/

var objectDescend = function () {
    var obj = arguments[0];
    var keys = arguments;
    var cur = obj;

    for (var i=1; i<keys.length; i++) {                                                                                                                                     
        var key = keys[i];                                                                                                                                                
        var cur = cur[key];                                                                                                                                               
        if(typeof(cur)=='undefined')                                                                                                                                      
            return cur;                                                                                                                                                   
    }      

    return cur;                                                                                                                                                           
}                                                                                                                                                                         

var test1 = {a:{b:{c:{d:1}}}};                                                                                                                                            
console.log(objectDescend(test1, 'a', 'b', 'c', 'd'));                                                                                                                
var test2 = {a:{b:{c:1}}};                                                                                                                                              
console.log(objectDescend(test2, 'a', 'b', 'c', 'd'));
于 2013-03-14T00:57:00.720 に答える