2014-12-13 83 views
1

我試圖訪問一個對象的屬性是這樣的:的Javascript獲取對象的屬性和子屬性

var scope1 = {a: {value: 25}}; 
var scope2 = undefined; 

var v1 = scope1.b.value || 0; // TypeError: Cannot read property 'value' of undefined 
var v2 = scope2.b.value || 0; // TypeError: Cannot read property 'value' of undefined 

apparentl的||操作員不給我我想要的。我知道我可以做以下代替

var vv2 = (scope1 && scope1.b ? scope1.b.value : 0); 

但是這使得代碼確實冗長的...所以任何人都知道,如果有更簡單的方法做我想做的事?謝謝。

回答

4

通常的答案是&&操作:

var v1 = scope1.b && scope1.b.value || 0; 

...因爲喜歡||&&curiously powerful&&評估左側操作數,如果它的falsey,採用的是falsey值作爲其結果;如果左側操作數值爲真,則&&將計算右側操作數並將該值作爲結果。

所以如果scope1.bundefined

// We start with 
scope1.b && scope1.b.value || 0 
// which is 
undefined && scope1.b.value || 0 
// which is 
undefined || 0 
// which is 
0 

...但如果scope.b就像是一個對象引用一個truthy值:

// We start with 
scope1.b && scope1.b.value || 0 
// which is 
scope1.b.value || 0 
// which is 
scope1.b.value // *IF* scope1.b.value is truthy, or 
0    // If it isn't 

(回想一下, 「falsey」 值是undefinednull,0,"",NaN,當然還有false;「truthy」值a重新所有其他)

例:

var scope1; 
 

 
scope1 = {a: "foo"}; 
 
snippet.log(scope1.b && scope1.b.value || 0); // 0 
 

 
scope1 = {a: "foo", b: {}}; 
 
snippet.log(scope1.b && scope1.b.value || 0); // 0 
 

 
scope1 = {a: "foo", b: {value: 42}}; 
 
snippet.log(scope1.b && scope1.b.value || 0); // 42
<!-- Script provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 --> 
 
<script src="http://tjcrowder.github.io/simple-snippets-console/snippet.js"></script>


我不推薦它,但你可以一個函數爲這個來處理任意深度:

function resolve(obj, path, defValue) { 
 
    var rv = path.split(".").reduce(function(o, p) { 
 
    return o && o[p]; 
 
    }, obj); 
 
    return rv || defValue; 
 
} 
 

 
var scope1; 
 

 
scope1 = {a: "foo"}; 
 
snippet.log(resolve(scope1, "b.value", 0)); // 0 
 

 
scope1 = {a: "foo", b: {}}; 
 
snippet.log(resolve(scope1, "b.value", 0)); // 0 
 

 
scope1 = {a: "foo", b: {value: 42}}; 
 
snippet.log(resolve(scope1, "b.value", 0)); // 42 
 

 
scope1 = {a: "foo", b: {}}; 
 
snippet.log(resolve(scope1, "b.baz.boz.value", 0)); // 0 
 

 
scope1 = {a: "foo", b: {baz: {boz: {value: 67}}}}; 
 
snippet.log(resolve(scope1, "b.baz.boz.value", 0)); // 67
<!-- Script provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 --> 
 
<script src="http://tjcrowder.github.io/simple-snippets-console/snippet.js"></script>

即實現不支持括號符號,只是點符號,但你可以自由地寫resolve(obj, "foo.0.bar.42", 0)如果你有你需要的數字指標,因爲它不符合標準的JavaScript解析規則。 (或者將其擴展到支持[]就不會那麼難)。

+0

明白了!這絕對有幫助!所以&&是最好的(或最短的代碼),我們可以用JavaScript做對嗎? – 2014-12-14 17:38:07

+0

@ChandlerLee:除非你想爲它編寫一個函數,並且執行'var v1 = foo(scope1,「b.value」,0);',這可能是過量的。 :-)我增加了一個這樣做的例子。最後幾個例子* *短於'var v1 = scope1.b && scope1.b.baz && scope1.b.baz.boz && scope1.b.baz.boz.value || 0;'會... – 2014-12-14 17:49:35