如果我有一个对象的引用:
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);
}
但我想知道是否有更好的方法。
如果您不想要 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 特性和递归(它也是 proper tail call 形式):
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
。
2019 年 10 月 17 日更新:
optional chaining proposal 在 ECMAScript committee process 上达到了第 3 阶段,这将允许您通过使用令牌 ?.
(新的可选链操作符)安全地访问深度嵌套的属性:
const value = obj?.level1?.level2?.level3
如果访问的任何级别是 null
或 undefined
,则表达式将自行解析为 undefined
。
该提案还允许您安全地处理方法调用:
obj?.level1?.method();
如果 obj
、obj.level1
或 obj.level1.method
是 null
或 undefined
,上述表达式将产生 undefined
,否则将调用该函数。
您可以使用 optional chaining plugin 通过 Babel 开始使用此功能。
自 Babel 7.8.0 起,默认支持 ES2020
检查 Babel REPL 上的 this example。
🎉🎉更新:2019 年 12 月🎉🎉
可选链提案最终在 2019 年 12 月的 TC39 委员会会议上reached Stage 4。这意味着此功能将成为 ECMAScript 2020 标准的一部分。
这是一个模式 I picked up from Oliver Steele:
var level3 = (((test || {}).level1 || {}).level2 || {}).level3;
alert( level3 );
事实上,整篇文章都是在讨论如何在 javascript 中做到这一点。他决定使用上述语法(一旦习惯了它就不会那么难读)作为习语。
(test || {})
的要点是,如果未定义测试,那么您正在执行 ({}.level1 || {})
。当然,{}.level1
是未定义的,所以这意味着您正在执行 {}.level2
,依此类推。
test
,则会出现 ReferenceError,但这不是问题,因为如果未声明,则存在要修复的错误,因此错误是一件好事。
if(test.level1 && test.level1.level2 && test.level1.level2.level3)
更新
看起来像 lodash has added _.get
可以满足您所有嵌套属性的需求。
_.get(countries, 'greece.sparta.playwright')
上一个答案
lodash 用户可能会喜欢具有 couple methods that mitigate this problem 的 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
我已经针对此问题提出的一些建议完成了 performance tests(感谢 cdMinix 添加 lodash),结果如下所示。
免责声明 #1 将字符串转换为引用是不必要的元编程,最好避免。不要一开始就忘记你的参考资料。从这个答案中阅读更多关于类似问题的信息。免责声明 #2 我们在这里谈论的是每毫秒数百万次操作。在大多数用例中,这些都不太可能产生很大的不同。在了解每个限制的情况下选择最有意义的那个。对我来说,出于方便,我会选择 reduce 之类的东西。
Object Wrap (by Oliver Steele) – 34 % – 最快
var r1 = (((test || {}).level1 || {}).level2 || {}).level3;
var r2 = (((test || {}).level1 || {}).level2 || {}).foo;
Original solution (suggested in question) – 45%
var r1 = test.level1 && test.level1.level2 && test.level1.level2.level3;
var r2 = test.level1 && test.level1.level2 && test.level1.level2.foo;
checkNested – 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 }
}
validChain – 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%
deeptest – 86%
function deeptest(target, s){
s= s.split('.')
var obj= target[s.shift()];
while(obj && s.length) obj= obj[s.shift()];
return obj;
}
sad clowns – 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 }
相比,它的性能如何
如果您像字符串一样处理名称:'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
。
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),那么您可以利用 arrow function 语法:
// ES6 using the arrow function
console.log(
isset(() => a.b.c),
isset(() => a.b.c.d.e.f)
);
关于性能,如果设置了属性,则使用 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
方法是最好的答案。查询对象的类型与假设 API 存在并且如果不存在则相应地失败之间存在哲学差异。后者更适合松散类型的语言。请参阅stackoverflow.com/a/408305/2419669。 try-catch
方法也比 if (foo && foo.bar && foo.bar.baz && foo.bar.baz.qux) { ... }
清晰得多。
怎么样
try {
alert(test.level1.level2.level3)
} catch(e) {
...whatever
}
hasOwnProperty()
n 次会更快吗?
您还可以将 tc39 可选链接提议与 babel 7 - tc39-proposal-optional-chaining 一起使用
代码如下所示:
const test = test?.level1?.level2?.level3;
if (test) alert(test);
ES6 答案,经过彻底测试:)
const propExists = (obj, path) => {
return !!path.split('.').reduce((obj, prop) => {
return obj && obj[prop] ? obj[prop] : undefined;
}, obj)
}
→ 参见 Codepen 完整的测试覆盖率
===
,并添加了测试。如果您有更好的想法,请告诉我)。
false
。然后您可能希望将对象中的值设置为 undefined
(我知道这很奇怪,但它是 JS)。我将正假值设置为 '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))
这个问题很老了。今天你可以使用可选链 (?.)
let value = test?.level1?.level2?.level3;
资源:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Optional_chaining
我尝试了一种递归方法:
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';
我认为以下脚本提供了更具可读性的表示。
声明一个函数:
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
但这一次智能感知有效!
另外,您可以设置默认值:
o(o(o(o(o(test).level1).level2).level3, "none")
°0o <°(())))><
Object
类型时,它会在你脸上抛出一个“未定义”。 +1。
创建一个全局 function
并在整个项目中使用
尝试这个
function isExist(arg){ try{ return arg(); }catch(e){ 返回 false; } } 让 obj={a:5,b:{c:5}}; console.log(isExist(()=>obj.bc)) console.log(isExist(()=>obj.b.foo)) console.log(isExist(()=>obj.test.foo))
如果条件
if(isExist(()=>obj.test.foo)){
....
}
我没有看到有人使用 Proxies 的任何示例
所以我想出了我自己的。它的好处是您不必插入字符串。您实际上可以返回一个可链接的对象函数并用它做一些神奇的事情。您甚至可以调用函数并获取数组索引来检查深层对象
function resolve(target) { var noop = () => {} // 我们是一个 noop 函数,所以我们可以调用方法也 return new Proxy(noop, { get(noop, key) { // 如果 key 是则返回最终结果_result return key === '_result' ? target : resolve( // 使用目标值或 undefined 解析 target === undefined ? undefined : target[key] ) }, // 如果我们想测试一个函数,那么我们可以这样做所以还要感谢使用 noop // 而不是在我们的代理中使用 target apply(noop, that, args) { return resolve(typeof target === 'function' ? target.apply(that, args) : undefined) }, } ) } // 已接受答案的一些修改示例 var test = {level1: {level2:() => ({level3:'level3'})}} var test1 = {key1: {key2: ['item0']} } // 最后需要得到_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) // 不存在
上面的代码适用于同步的东西。但是你将如何测试像这个 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) })) }, }) } // 这感觉非常同步,但仍然是非阻塞的 :) resolve(window) // this将链接一个 noop 函数,直到您调用 then() .fetch('https://httpbin.org/get') .json() .headers['User-Agent'] .then(console.log, console.warn) // 如果它不存在,您会收到警告 // 您也可以对第一个测试对象使用此方法 // 也可以,但最后必须调用 .then() // 另一个示例 resolve(window) .fetch('https://httpbin.org/get?items=4&items=2') .json() .args .items // 很高兴你可以在没有准备好的情况下映射一个数组项 .map(n => ~~n * 4) .then(console.log, console.warn) / / 如果它不存在,您会收到警告
一种简单的方法是:
try {
alert(test.level1.level2.level3);
} catch(e) {
alert("undefined"); // this is optional to put any output here
}
try/catch
捕获未定义任何更高级别对象(例如 test、test.level1、test.level1.level2)的情况。
基于 this answer,我使用 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 }
我创建了一个小函数来安全地获取嵌套对象属性。
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);
}
甚至更短但不使用 falsy 标志:
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
@CMS 优秀答案的更短的 ES5 版本:
// 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 的答案。这是我想出的:
function getNestedProperty(obj, key) { // 从键字符串中获取属性数组 var properties = key.split("."); // 遍历属性,如果对象为 null 或属性不存在则返回 undefined for (var i = 0; i < properties.length; i++) { if (!obj || !obj.hasOwnProperty(properties[i]) ) { 返回; } obj = obj[属性[i]]; } // 找到嵌套属性,所以返回值 return obj; } 用法:getNestedProperty(test, "level1.level2.level3") // "level3" getNestedProperty(test, "level1.level2.foo") // 未定义
CMS 给出的答案也适用于空检查的以下修改
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;
}
从 this answer 开始详细阐述了以下选项。两者相同的树:
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
我知道这个问题很老,但我想通过将它添加到所有对象来提供扩展。我知道人们倾向于不赞成使用对象原型来扩展对象功能,但我没有发现比这样做更容易的事情了。另外,现在允许使用 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") )
Here's a jsfiddle 对其进行测试,特别是它包含一些 jQuery,如果您直接修改 Object.prototype 会中断,因为该属性变得可枚举。这应该适用于 3rd 方库。
我认为这是一个轻微的改进(成为 1-liner):
alert( test.level1 && test.level1.level2 && test.level1.level2.level3 )
这是有效的,因为 && 运算符返回它评估的最终操作数(并且它短路)。
这适用于所有对象和数组:)
前任:
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;
}});
这是fiddle
这是我的看法 - 这些解决方案中的大多数都忽略了嵌套数组的情况,如下所示:
obj = {
"l1":"something",
"l2":[{k:0},{k:1}],
"l3":{
"subL":"hello"
}
}
我可能想检查 obj.l2[0].k
使用下面的函数,您可以执行 deeptest('l2[0].k',obj)
如果对象存在,该函数将返回 true,否则返回 false
函数 deeptest(keyPath, testObj) { var obj; keyPath = keyPath.split('.') var cKey = keyPath.shift();函数get(pObj,pKey){var括号开始,括号结束,o;括号开始 = pKey.indexOf("["); if (bracketStart > -1) { //检查嵌套数组bracketEnd = pKey.indexOf("]"); var arrIndex = pKey.substr(bracketStart + 1, 括号结束 - 括号开始 - 1); pKey = pKey.substr(0, 括号开始); var n = pObj[pKey]; o = n? n[arrIndex]:未定义; } 其他 { o = pObj[pKey]; } 返回 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 ":"字母 A", "b":"字母 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));
现在我们还可以使用 reduce
循环遍历嵌套键:
// @params o
您可以使用递归函数来做到这一点。即使您不知道所有嵌套的对象键名称,这也将起作用。
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;
}
还有一个非常紧凑的:
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
它不会表现得很好,因为它正在拆分字符串(但增加了调用的可读性)并迭代所有内容,即使已经很明显什么都不会找到(但增加了函数本身的可读性)。
至少比 _.get
http://jsben.ch/aAtmc 快
我已经使用这个函数来访问深度嵌套对象的属性,它对我有用......
这是功能
/**
* 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') }}
您可以尝试 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
有一个用于 optinal chaning 的 babel 插件(@babel/plugin-proposal-optional-chaining
)。因此,如有必要,请升级您的 babel。
不定期副业成功案例分享
arguments
实际上不是一个数组。Array.prototype.slice.call(arguments)
将其转换为正式数组。 Learnvar obj = arguments[0];
并从var i = 1
开始,而不是复制arguments
对象args
变量声明,并且可以将...args
用作checkNested
方法的第二个参数。 developer.mozilla.org/en/docs/Web/JavaScript/Reference/…