提问人:user113716 提问时间:4/13/2010 最后编辑:Bergiuser113716 更新时间:1/14/2022 访问量:402824
测试嵌套 JavaScript 对象键是否存在
Test for existence of nested JavaScript object key
问:
如果我有对某个对象的引用:
var test = {};
它可能会(但不是立即)有嵌套对象,例如:
{level1: {level2: {level3: "level3"}}};
检查深度嵌套对象中是否存在属性的最佳方法是什么?
alert(test.level1);
产生,但失败。undefined
alert(test.level1.level2.level3);
我目前正在做这样的事情:
if(test.level1 && test.level1.level2 && test.level1.level2.level3) {
alert(test.level1.level2.level3);
}
但我想知道是否有更好的方法。
答:
怎么样
try {
alert(test.level1.level2.level3)
} catch(e) {
...whatever
}
评论
hasOwnProperty()
如果你不想要一个,你必须一步一步地去做,因为如果其中一个成员是 或 ,并且你尝试访问一个成员,就会抛出一个异常。TypeError
null
undefined
你可以简单地选择异常,也可以创建一个函数来测试多个级别的存在,如下所示:catch
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
ES6 更新:
这是原始函数的较短版本,使用 ES6 特性和递归(它也采用适当的尾部调用形式):
function checkNested(obj, level, ...rest) {
if (obj === undefined) return false
if (rest.length == 0 && obj.hasOwnProperty(level)) return true
return checkNested(obj[level], ...rest)
}
但是,如果您想获取嵌套属性的值,而不仅仅是检查其存在,这里有一个简单的单行函数:
function getNested(obj, ...args) {
return args.reduce((obj, level) => obj && obj[level], obj)
}
const test = { level1:{ level2:{ level3:'level3'} } };
console.log(getNested(test, 'level1', 'level2', 'level3')); // 'level3'
console.log(getNested(test, 'level1', 'level2', 'level3', 'length')); // 6
console.log(getNested(test, 'level1', 'level2', 'foo')); // undefined
console.log(getNested(test, 'a', 'b')); // undefined
上面的函数允许你获取嵌套属性的值,否则将返回 .undefined
更新 2019-10-17:
可选链接提案在 ECMAScript 委员会进程中达到了第 3 阶段,这将允许您通过使用令牌安全地访问深度嵌套的属性,即新的可选链接运算符:?.
const value = obj?.level1?.level2?.level3
如果访问的任何级别是 或表达式将自行解析。null
undefined
undefined
该提案还允许您安全地处理方法调用:
obj?.level1?.method();
上面的表达式将生成 if , , , or are 或 ,否则它将调用该函数。undefined
obj
obj.level1
obj.level1.method
null
undefined
您可以使用可选的链接插件开始在 Babel 上玩此功能。
从 Babel 7.8.0 开始,默认支持 ES2020
在 Babel REPL 上查看此示例。
🎉🎉更新时间:2019 🎉🎉 年 12 月
在 2019 年 12 月的 TC39 委员会会议上,可选链接提案最终进入了第 4 阶段。这意味着此功能将成为 ECMAScript 2020 标准的一部分。
评论
args
...args
checkNested
您可以读取任何深度的对象属性,前提是像处理字符串一样处理名称:。't.level1.level2.level3'
window.t={level1:{level2:{level3: 'level3'}}};
function deeptest(s){
s= s.split('.')
var obj= window[s.shift()];
while(obj && s.length) obj= obj[s.shift()];
return obj;
}
alert(deeptest('t.level1.level2.level3') || 'Undefined');
如果任何段是 ,则返回 。undefined
undefined
评论
这是我从奥利弗·斯蒂尔(Oliver Steele)那里学到的一个模式:
var level3 = (((test || {}).level1 || {}).level2 || {}).level3;
alert( level3 );
事实上,整篇文章都在讨论如何在 javascript 中做到这一点。他决定使用上述语法(一旦你习惯了它,就不难读了)作为成语。
评论
(test || {})
({}.level1 || {})
{}.level1
{}.level2
test
if(test.level1 && test.level1.level2 && test.level1.level2.level3)
一个简单的方法是:
try {
alert(test.level1.level2.level3);
} catch(e) {
alert("undefined"); // this is optional to put any output here
}
捕获未定义任何更高级别的对象(如 test、test.level1、test.level1.level2)的情况。try/catch
一个更短的 ES5 版本,@CMS的出色答案:
// Check the obj has the keys in the order mentioned. Used for checking JSON results.
var checkObjHasKeys = function(obj, keys) {
var success = true;
keys.forEach( function(key) {
if ( ! obj.hasOwnProperty(key)) {
success = false;
}
obj = obj[key];
})
return success;
}
通过类似的测试:
var test = { level1:{level2:{level3:'result'}}};
utils.checkObjHasKeys(test, ['level1', 'level2', 'level3']); // true
utils.checkObjHasKeys(test, ['level1', 'level2', 'foo']); // false
评论
checkObjHasKeys(test, ['level1', 'level2', 'asdf', 'asdf']);
success = false;
return false
CMS给出的答案也可以通过以下修改来进行null检查
function checkNested(obj /*, level1, level2, ... levelN*/)
{
var args = Array.prototype.slice.call(arguments),
obj = args.shift();
for (var i = 0; i < args.length; i++)
{
if (obj == null || !obj.hasOwnProperty(args[i]) )
{
return false;
}
obj = obj[args[i]];
}
return true;
}
从这个答案开始,详细阐述了以下选项。两者的同一棵树:
var o = { a: { b: { c: 1 } } };
未定义时停止搜索
var u = undefined;
o.a ? o.a.b ? o.a.b.c : u : u // 1
o.x ? o.x.y ? o.x.y.z : u : u // undefined
(o = o.a) ? (o = o.b) ? o.c : u : u // 1
逐一确保每个级别
var $ = function (empty) {
return function (node) {
return node || empty;
};
}({});
$($(o.a).b).c // 1
$($(o.x).y).z // undefined
我尝试了一种递归方法:
function objHasKeys(obj, keys) {
var next = keys.shift();
return obj[next] && (! keys.length || objHasKeys(obj[next], keys));
}
踢出递归,因此它不会在没有键的情况下运行函数进行测试。测试:! keys.length ||
obj = {
path: {
to: {
the: {
goodKey: "hello"
}
}
}
}
console.log(objHasKeys(obj, ['path', 'to', 'the', 'goodKey'])); // true
console.log(objHasKeys(obj, ['path', 'to', 'the', 'badKey'])); // undefined
我正在使用它来打印一堆具有未知键/值的对象的友好 html 视图,例如:
var biosName = objHasKeys(myObj, 'MachineInfo:BiosInfo:Name'.split(':'))
? myObj.MachineInfo.BiosInfo.Name
: 'unknown';
更新
看起来 lodash 已经为您所有的嵌套属性获取需求添加了内容。_.get
_.get(countries, 'greece.sparta.playwright')
上一个答案
Lodash 用户可能会喜欢 Lodash.contrib,它有几种方法可以缓解这个问题。
获取路径
签名: _.getPath(obj:Object, ks:String|Array)
根据
给出的钥匙。键可以作为数组或点分隔字符串提供。
如果无法访问路径,则返回。undefined
var countries = {
greece: {
athens: {
playwright: "Sophocles"
}
}
}
};
_.getPath(countries, "greece.athens.playwright");
// => "Sophocles"
_.getPath(countries, "greece.sparta.playwright");
// => undefined
_.getPath(countries, ["greece", "athens", "playwright"]);
// => "Sophocles"
_.getPath(countries, ["greece", "sparta", "playwright"]);
// => undefined
评论
function isPathDefined(object, path) { return typeof _.getPath(object, path) !== 'undefined'; }
_.get(countries, 'greece.sparta.playwright', 'default'); // → 'default' _.has(countries, 'greece.spart.playwright') // → false
var url = _.get(e, 'currentTarget.myurl', null) || _.get(e, 'currentTarget.attributes.myurl.nodeValue', null) || null
var a;
a = {
b: {
c: 'd'
}
};
function isset (fn) {
var value;
try {
value = fn();
} catch (e) {
value = undefined;
} finally {
return value !== undefined;
}
};
// ES5
console.log(
isset(function () { return a.b.c; }),
isset(function () { return a.b.c.d.e.f; })
);
如果您在 ES6 环境中编码(或使用 6to5),那么您可以利用箭头函数语法:
// ES6 using the arrow function
console.log(
isset(() => a.b.c),
isset(() => a.b.c.d.e.f)
);
关于性能,如果设置了该属性,则使用 block 不会对性能造成损害。如果未设置该属性,则会影响性能。try..catch
考虑简单地使用 _.has
:
var object = { 'a': { 'b': { 'c': 3 } } };
_.has(object, 'a');
// → true
_.has(object, 'a.b.c');
// → true
_.has(object, ['a', 'b', 'c']);
// → true
评论
try-catch
try-catch
if (foo && foo.bar && foo.bar.baz && foo.bar.baz.qux) { ... }
我知道这个问题很老,但我想通过将其添加到所有对象来提供扩展。我知道人们倾向于不赞成将 Object 原型用于扩展对象功能,但我发现没有什么比这样做更容易的了。此外,现在允许使用 Object.defineProperty 方法。
Object.defineProperty( Object.prototype, "has", { value: function( needle ) {
var obj = this;
var needles = needle.split( "." );
for( var i = 0; i<needles.length; i++ ) {
if( !obj.hasOwnProperty(needles[i])) {
return false;
}
obj = obj[needles[i]];
}
return true;
}});
现在,为了测试任何对象中的任何属性,您可以简单地执行以下操作:
if( obj.has("some.deep.nested.object.somewhere") )
这里有一个 jsfiddle 来测试它,特别是它包含一些 jQuery,如果你直接修改 Object.prototype,因为该属性变得可枚举,它就会中断。这应该适用于第三方库。
我认为这是一个轻微的改进(成为 1 行):
alert( test.level1 && test.level1.level2 && test.level1.level2.level3 )
这是有效的,因为&&运算符返回它计算的最终操作数(并且短路)。
评论
如果属性存在,我一直在寻找要返回的值,因此我修改了上面CMS的答案。这是我想出的:
function getNestedProperty(obj, key) {
// Get property array from key string
var properties = key.split(".");
// Iterate through properties, returning undefined if object is null or property doesn't exist
for (var i = 0; i < properties.length; i++) {
if (!obj || !obj.hasOwnProperty(properties[i])) {
return;
}
obj = obj[properties[i]];
}
// Nested property found, so return the value
return obj;
}
Usage:
getNestedProperty(test, "level1.level2.level3") // "level3"
getNestedProperty(test, "level1.level2.foo") // undefined
这是我的看法 - 这些解决方案中的大多数都忽略了嵌套数组的情况,如下所示:
obj = {
"l1":"something",
"l2":[{k:0},{k:1}],
"l3":{
"subL":"hello"
}
}
我可能想检查一下obj.l2[0].k
使用以下功能,您可以做到deeptest('l2[0].k',obj)
如果对象存在,则该函数将返回 true,否则返回 false
function deeptest(keyPath, testObj) {
var obj;
keyPath = keyPath.split('.')
var cKey = keyPath.shift();
function get(pObj, pKey) {
var bracketStart, bracketEnd, o;
bracketStart = pKey.indexOf("[");
if (bracketStart > -1) { //check for nested arrays
bracketEnd = pKey.indexOf("]");
var arrIndex = pKey.substr(bracketStart + 1, bracketEnd - bracketStart - 1);
pKey = pKey.substr(0, bracketStart);
var n = pObj[pKey];
o = n? n[arrIndex] : undefined;
} else {
o = pObj[pKey];
}
return o;
}
obj = get(testObj, cKey);
while (obj && keyPath.length) {
obj = get(obj, keyPath.shift());
}
return typeof(obj) !== 'undefined';
}
var obj = {
"l1":"level1",
"arr1":[
{"k":0},
{"k":1},
{"k":2}
],
"sub": {
"a":"letter A",
"b":"letter B"
}
};
console.log("l1: " + deeptest("l1",obj));
console.log("arr1[0]: " + deeptest("arr1[0]",obj));
console.log("arr1[1].k: " + deeptest("arr1[1].k",obj));
console.log("arr1[1].j: " + deeptest("arr1[1].j",obj));
console.log("arr1[3]: " + deeptest("arr1[3]",obj));
console.log("arr2: " + deeptest("arr2",obj));
这适用于所有对象和数组:)
前任:
if( obj._has( "something.['deep']['under'][1][0].item" ) ) {
//do something
}
这是我对布莱恩答案的改进版本
我使用 _has 作为属性名称,因为它可能与现有的 has 属性(例如:地图)冲突
Object.defineProperty( Object.prototype, "_has", { value: function( needle ) {
var obj = this;
var needles = needle.split( "." );
var needles_full=[];
var needles_square;
for( var i = 0; i<needles.length; i++ ) {
needles_square = needles[i].split( "[" );
if(needles_square.length>1){
for( var j = 0; j<needles_square.length; j++ ) {
if(needles_square[j].length){
needles_full.push(needles_square[j]);
}
}
}else{
needles_full.push(needles[i]);
}
}
for( var i = 0; i<needles_full.length; i++ ) {
var res = needles_full[i].match(/^((\d+)|"(.+)"|'(.+)')\]$/);
if (res != null) {
for (var j = 0; j < res.length; j++) {
if (res[j] != undefined) {
needles_full[i] = res[j];
}
}
}
if( typeof obj[needles_full[i]]=='undefined') {
return false;
}
obj = obj[needles_full[i]];
}
return true;
}});
这是小提琴
我认为以下脚本提供了更具可读性的表示。
声明一个函数:
var o = function(obj) { return obj || {};};
然后像这样使用它:
if (o(o(o(o(test).level1).level2).level3)
{
}
我称它为“悲伤的小丑技术”,因为它使用符号 o(
编辑:
这是 TypeScript 的一个版本
它在编译时提供类型检查(如果使用 Visual Studio 等工具,则提供智能感知)
export function o<T>(someObject: T, defaultValue: T = {} as T) : T {
if (typeof someObject === 'undefined' || someObject === null)
return defaultValue;
else
return someObject;
}
用法是一样的:
o(o(o(o(test).level1).level2).level3
但这次 IntelliSense 有效了!
另外,您可以设置默认值:
o(o(o(o(o(test).level1).level2).level3, "none")
评论
°0o <°(())))><
Object
基于这个答案,我想出了这个通用函数,用它来解决问题ES2015
function validChain( object, ...keys ) {
return keys.reduce( ( a, b ) => ( a || { } )[ b ], object ) !== undefined;
}
var test = {
first: {
second: {
third: "This is not the key your are looking for"
}
}
}
if ( validChain( test, "first", "second", "third" ) ) {
console.log( test.first.second.third );
}
评论
function validChain (object, path) { return path.split('.').reduce((a, b) => (a || { })[b], object) !== undefined }
我已经对针对这个问题提出的一些建议进行了性能测试(感谢 cdMinix 添加 lodash),结果如下。
免责声明 #1将字符串转换为引用是不必要的元编程,最好避免。不要一开始就忘记你的参考资料。从这个类似问题的答案中阅读更多内容。
免责声明 #2我们在这里谈论的是每毫秒数百万次操作。在大多数用例中,这些都不太可能产生太大影响。选择最有意义的一个,了解每个的局限性。对我来说,出于方便,我会选择类似的东西。
reduce
对象包装(作者:Oliver Steele) – 34 % – 最快
var r1 = (((test || {}).level1 || {}).level2 || {}).level3;
var r2 = (((test || {}).level1 || {}).level2 || {}).foo;
原始解决方案(有问题的建议)– 45%
var r1 = test.level1 && test.level1.level2 && test.level1.level2.level3;
var r2 = test.level1 && test.level1.level2 && test.level1.level2.foo;
check嵌套 – 50%
function checkNested(obj) {
for (var i = 1; i < arguments.length; i++) {
if (!obj.hasOwnProperty(arguments[i])) {
return false;
}
obj = obj[arguments[i]];
}
return true;
}
get_if_exist – 52%
function get_if_exist(str) {
try { return eval(str) }
catch(e) { return undefined }
}
有效链 – 54%
function validChain( object, ...keys ) {
return keys.reduce( ( a, b ) => ( a || { } )[ b ], object ) !== undefined;
}
objHasKeys – 63%
function objHasKeys(obj, keys) {
var next = keys.shift();
return obj[next] && (! keys.length || objHasKeys(obj[next], keys));
}
nestedPropertyExists – 69%
function nestedPropertyExists(obj, props) {
var prop = props.shift();
return prop === undefined ? true : obj.hasOwnProperty(prop) ? nestedPropertyExists(obj[prop], props) : false;
}
_.get – 72%
深度测试 – 86%
function deeptest(target, s){
s= s.split('.')
var obj= target[s.shift()];
while(obj && s.length) obj= obj[s.shift()];
return obj;
}
悲伤的小丑 – 100% – 最慢
var o = function(obj) { return obj || {} };
var r1 = o(o(o(o(test).level1).level2).level3);
var r2 = o(o(o(o(test).level1).level2).foo);
评论
_.get()
reduce
try/catch
try { test.level1.level2.level3 } catch (e) { // some logger e }
现在,我们还可以使用 to 循环访问嵌套键:reduce
// @params o<object>
// @params path<string> expects 'obj.prop1.prop2.prop3'
// returns: obj[path] value or 'false' if prop doesn't exist
const objPropIfExists = o => path => {
const levels = path.split('.');
const res = (levels.length > 0)
? levels.reduce((a, c) => a[c] || 0, o)
: o[path];
return (!!res) ? res : false
}
const obj = {
name: 'Name',
sys: { country: 'AU' },
main: { temp: '34', temp_min: '13' },
visibility: '35%'
}
const exists = objPropIfExists(obj)('main.temp')
const doesntExist = objPropIfExists(obj)('main.temp.foo.bar.baz')
console.log(exists, doesntExist)
我没有看到任何有人使用代理的例子
所以我想出了自己的。
它的好处是你不必插值字符串。你实际上可以返回一个可链接的对象函数,并用它做一些神奇的事情。您甚至可以调用函数并获取数组索引来检查深层对象
function resolve(target) {
var noop = () => {} // We us a noop function so we can call methods also
return new Proxy(noop, {
get(noop, key) {
// return end result if key is _result
return key === '_result'
? target
: resolve( // resolve with target value or undefined
target === undefined ? undefined : target[key]
)
},
// if we want to test a function then we can do so alos thanks to using noop
// instead of using target in our proxy
apply(noop, that, args) {
return resolve(typeof target === 'function' ? target.apply(that, args) : undefined)
},
})
}
// some modified examples from the accepted answer
var test = {level1: {level2:() => ({level3:'level3'})}}
var test1 = {key1: {key2: ['item0']}}
// You need to get _result in the end to get the final result
console.log(resolve(test).level1.level2().level3._result)
console.log(resolve(test).level1.level2().level3.level4.level5._result)
console.log(resolve(test1).key1.key2[0]._result)
console.log(resolve(test1)[0].key._result) // don't exist
上面的代码适用于同步的东西。但是,您将如何测试像此 ajax 调用这样的异步内容? 你如何测试它?
fetch('https://httpbin.org/get')
.then(function(response) {
return response.json()
})
.then(function(json) {
console.log(json.headers['User-Agent'])
})
当然,您可以使用 async/await 来摆脱一些回调。但是,如果你能更神奇地做到这一点呢?看起来像这样的东西:
fetch('https://httpbin.org/get').json().headers['User-Agent']
你可能想知道所有的承诺和链条在哪里......这可能是你所知道的一切的障碍......但是使用相同的代理技术,您实际上可以测试深度嵌套的复杂路径,而无需编写单个函数.then
function resolve(target) {
return new Proxy(() => {}, {
get(noop, key) {
return key === 'then' ? target.then.bind(target) : resolve(
Promise.resolve(target).then(target => {
if (typeof target[key] === 'function') return target[key].bind(target)
return target[key]
})
)
},
apply(noop, that, args) {
return resolve(target.then(result => {
return result.apply(that, args)
}))
},
})
}
// this feels very much synchronous but are still non blocking :)
resolve(window) // this will chain a noop function until you call then()
.fetch('https://httpbin.org/get')
.json()
.headers['User-Agent']
.then(console.log, console.warn) // you get a warning if it doesn't exist
// You could use this method also for the first test object
// also, but it would have to call .then() in the end
// Another example
resolve(window)
.fetch('https://httpbin.org/get?items=4&items=2')
.json()
.args
.items
// nice that you can map an array item without even having it ready
.map(n => ~~n * 4)
.then(console.log, console.warn) // you get a warning if it doesn't exist
评论
您可以使用递归函数来执行此操作。即使您不知道所有嵌套的对象键名称,这也将起作用。
function FetchKeys(obj) {
let objKeys = [];
let keyValues = Object.entries(obj);
for (let i in keyValues) {
objKeys.push(keyValues[i][0]);
if (typeof keyValues[i][1] == "object") {
var keys = FetchKeys(keyValues[i][1])
objKeys = objKeys.concat(keys);
}
}
return objKeys;
}
let test = { level1: { level2: { level3: "level3" } } };
let keyToCheck = "level2";
let keys = FetchKeys(test); //Will return an array of Keys
if (keys.indexOf(keyToCheck) != -1) {
//Key Exists logic;
}
else {
//Key Not Found logic;
}
ES6 答案,经过全面测试:)
const propExists = (obj, path) => {
return !!path.split('.').reduce((obj, prop) => {
return obj && obj[prop] ? obj[prop] : undefined;
}, obj)
}
→请参阅具有完整测试覆盖率的 Codepen
评论
false
undefined
'Prop not Found'
const hasTruthyProp = prop => prop === 'Prop not found' ? false : true const path = obj => path => path.reduce((obj, prop) => { return obj && obj.hasOwnProperty(prop) ? obj[prop] : 'Prop not found' }, obj) const myFunc = compose(hasTruthyProp, path(obj))
您也可以将 tc39 可选链接提案与 babel 7 一起使用 - tc39-proposal-optional-chaining
代码如下所示:
const test = test?.level1?.level2?.level3;
if (test) alert(test);
评论
我创建了一个小函数来安全地获取嵌套对象属性。
function getValue(object, path, fallback, fallbackOnFalsy) {
if (!object || !path) {
return fallback;
}
// Reduces object properties to the deepest property in the path argument.
return path.split('.').reduce((object, property) => {
if (object && typeof object !== 'string' && object.hasOwnProperty(property)) {
// The property is found but it may be falsy.
// If fallback is active for falsy values, the fallback is returned, otherwise the property value.
return !object[property] && fallbackOnFalsy ? fallback : object[property];
} else {
// Returns the fallback if current chain link does not exist or it does not contain the property.
return fallback;
}
}, object);
}
或者一个更简单但有点不可读的版本:
function getValue(o, path, fb, fbFalsy) {
if(!o || !path) return fb;
return path.split('.').reduce((o, p) => o && typeof o !== 'string' && o.hasOwnProperty(p) ? !o[p] && fbFalsy ? fb : o[p] : fb, o);
}
甚至更短,但没有回退假旗:
function getValue(o, path, fb) {
if(!o || !path) return fb;
return path.split('.').reduce((o, p) => o && typeof o !== 'string' && o.hasOwnProperty(p) ? o[p] : fb, o);
}
我有测试:
const obj = {
c: {
a: 2,
b: {
c: [1, 2, 3, {a: 15, b: 10}, 15]
},
c: undefined,
d: null
},
d: ''
}
以下是一些测试:
// null
console.log(getValue(obj, 'c.d', 'fallback'));
// array
console.log(getValue(obj, 'c.b.c', 'fallback'));
// array index 2
console.log(getValue(obj, 'c.b.c.2', 'fallback'));
// no index => fallback
console.log(getValue(obj, 'c.b.c.10', 'fallback'));
要查看所有带有文档的代码和我尝试过的测试,您可以查看我的 github 要点: https://gist.github.com/vsambor/3df9ad75ff3de489bbcb7b8c60beebf4#file-javascriptgetnestedvalues-js
还有另一个非常紧凑的:
function ifSet(object, path) {
return path.split('.').reduce((obj, part) => obj && obj[part], object)
}
叫:
let a = {b:{c:{d:{e:'found!'}}}}
ifSet(a, 'b.c.d.e') == 'found!'
ifSet(a, 'a.a.a.a.a.a') == undefined
它不会表现得很好,因为它正在拆分一个字符串(但增加了调用的可读性)并遍历所有内容,即使已经很明显什么都找不到(但增加了函数本身的可读性)。
至少比 http://jsben.ch/aAtmc 快_.get
创建全局并在整个项目中使用function
试试这个
function isExist(arg){
try{
return arg();
}catch(e){
return false;
}
}
let obj={a:5,b:{c:5}};
console.log(isExist(()=>obj.b.c))
console.log(isExist(()=>obj.b.foo))
console.log(isExist(()=>obj.test.foo))
if 条件
if(isExist(()=>obj.test.foo)){
....
}
评论
我已经使用这个函数来访问深度嵌套对象的属性,它对我有用......
这是函数
/**
* get property of object
* @param obj object
* @param path e.g user.name
*/
getProperty(obj, path, defaultValue = '-') {
const value = path.split('.').reduce((o, p) => o && o[p], obj);
return value ? value : defaultValue;
}
这就是我访问深度嵌套对象属性的方式
{{ getProperty(object, 'passengerDetails.data.driverInfo.currentVehicle.vehicleType') }}
这个问题很老了。今天,您可以使用可选链接 (?.)
let value = test?.level1?.level2?.level3;
源:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Optional_chaining
评论
您可以尝试可选链接
(但要注意浏览器兼容性)。
let test = {level1: {level2: {level3: 'level3'}}};
let level3 = test?.level1?.level2?.level3;
console.log(level3); // level3
level3 = test?.level0?.level1?.level2?.level3;
console.log(level3); // undefined
有一个 babel 插件(@babel/plugin-proposal-optional-chaining
)用于选择性切换。所以,如有必要,请升级你的通天塔。
评论