测试是否存在嵌套的JavaScript对象键
如果我对某个对象有引用:测试是否存在嵌套的JavaScript对象键,javascript,object,properties,nested,Javascript,Object,Properties,Nested,如果我对某个对象有引用: var test = {}; 可能(但不是立即)具有嵌套对象的对象,例如: {level1: {level2: {level3: "level3"}}}; 检查深度嵌套对象中是否存在属性的最佳方法是什么 警报(测试级别1)产生未定义,但发出警报(test.level1.level2.level3)失败 我目前正在做这样的事情: if(test.level1 && test.level1.level2 && test.level1.le
var test = {};
可能(但不是立即)具有嵌套对象的对象,例如:
{level1: {level2: {level3: "level3"}}};
检查深度嵌套对象中是否存在属性的最佳方法是什么
警报(测试级别1)代码>产生未定义
,但发出警报(test.level1.level2.level3)代码>失败
我目前正在做这样的事情:
if(test.level1 && test.level1.level2 && test.level1.level2.level3) {
alert(test.level1.level2.level3);
}
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
if (o(o(o(o(test).level1).level2).level3)
{
}
const test = test?.level1?.level2?.level3;
if (test) alert(test);
但是我想知道是否有更好的办法。怎么样
try {
alert(test.level1.level2.level3)
} catch(e) {
...whatever
}
如果您不希望出现类型错误
,则必须一步一步地执行此操作,因为如果其中一个成员为null
或未定义
,并且您尝试访问一个成员,将引发异常
您可以简单地捕获
异常,或者创建一个函数来测试是否存在多个级别,如下所示:
if(test.level1 && test.level1.level2 && test.level1.level2.level3) {
alert(test.level1.level2.level3);
}
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
if (o(o(o(o(test).level1).level2).level3)
{
}
const test = test?.level1?.level2?.level3;
if (test) alert(test);
但是,如果您希望获取嵌套属性的值,而不仅仅是检查其存在性,那么这里有一个简单的单行函数:
var o = function(obj) { return obj || {};};
函数getNested(obj,…args){
返回参数reduce((对象,级别)=>obj&&obj[level],obj)
}
常量测试={level1:{level2:{level3:'level3'}};
log(getNested(测试'level1','level2','level3');/'三级'
log(getNested(测试'level1','level2','level3','length');//6.
log(getNested(测试'level1','level2','foo');//未定义
log(getNested(测试'a','b');//未定义
如果像字符串一样处理名称,则可以在任何深度读取对象属性:'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');
如果任何段未定义
,则返回未定义
以下是模式I:
事实上,整篇文章讨论了如何使用javascript实现这一点。他决定将上述语法(一旦你习惯了就不难理解)作为一种习语使用。一个简单的方法是:
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)的情况。一个简短的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
有一个函数将以安全的方式执行此操作。。。i、 e
safeRead(test, 'level1', 'level2', 'level3');
如果任何属性为null或未定义,则返回一个空字符串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;
}
函数checkNested(obj/*,level1,level2,…levelN*/)
{
var args=Array.prototype.slice.call(参数),
obj=args.shift();
对于(变量i=0;i
以下选项从一开始就进行了详细阐述。两者的树相同:
var o = { a: { b: { c: 1 } } };
未定义时停止搜索
逐级保证
我尝试了一种递归方法:
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(countries, 'greece.sparta.playwright')
先前的答复
用户可以享受其中有一个
获取路径
签名:.getPath(obj:Object,ks:String | Array)
获取嵌套对象中任意深度处的值,该值基于
钥匙是给你的。键可以作为数组或点分隔字符串给出。
如果无法到达路径,则返回未定义的
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
如果您在ES6环境中编码(或使用),则可以利用以下语法:
关于性能,如果设置了属性,则使用try..catch
块不会导致性能损失。如果属性未设置,则会影响性能
考虑简单地使用:
我编写了自己的函数,该函数采用所需的路径,并且有一个好的回调函数和一个坏的回调函数
function checkForPathInObject(object, path, callbackGood, callbackBad){
var pathParts = path.split(".");
var currentObjectPath = object;
// Test every step to see if it exists in object
for(var i=0; i<(pathParts.length); i++){
var currentPathPart = pathParts[i];
if(!currentObjectPath.hasOwnProperty(pathParts[i])){
if(callbackBad){
callbackBad();
}
return false;
} else {
currentObjectPath = currentObjectPath[pathParts[i]];
}
}
// call full path in callback
callbackGood();
}
我知道这个问题很老,但我想通过将它添加到所有对象来提供一个扩展。我知道人们倾向于不赞成使用对象原型来扩展对象功能,但我发现没有什么比这更容易的了。另外,现在允许使用该方法
为了测试它,特别是它包含一些jQuery,如果您直接修改Object.prototype,因为属性变得可枚举,那么jQuery就会中断。这在第三方库中应该可以很好地使用。//以防万一您的框架不支持或不包括
//Just in case is not supported or not included by your framework
//***************************************************
Array.prototype.some = function(fn, thisObj) {
var scope = thisObj || window;
for ( var i=0, j=this.length; i < j; ++i ) {
if ( fn.call(scope, this[i], i, this) ) {
return true;
}
}
return false;
};
//****************************************************
function isSet (object, string) {
if (!object) return false;
var childs = string.split('.');
if (childs.length > 0 ) {
return !childs.some(function (item) {
if (item in object) {
object = object[item];
return false;
} else return true;
});
} else if (string in object) {
return true;
} else return false;
}
var object = {
data: {
item: {
sub_item: {
bla: {
here : {
iam: true
}
}
}
}
}
};
console.log(isSet(object,'data.item')); // true
console.log(isSet(object,'x')); // false
console.log(isSet(object,'data.sub_item')); // false
console.log(isSet(object,'data.item')); // true
console.log(isSet(object,'data.item.sub_item.bla.here.iam')); // true
//***************************************************
Array.prototype.some=函数(fn,thisObj){
var范围=此OBJ | |窗口;
对于(变量i=0,j=this.length;i0){
return!childs.some(函数(项){
if(对象中的项){
对象=对象[项目];
返回false;
}否则返回true;
});
}如果(对象中的字符串){
返回true;
}否则返回false;
}
变量对象={
数据:{
项目:{
分项:{
布莱:{
在这里:{
是的
}
}
}
}
}
};
console.log(isSet(对象,'data.item'));//真的
log(isSet(对象,'x'));//假的
console.log(isSet(对象,'data.sub_item'));//假的
console.log(isSet(对象,'data.item'));//真的
log(isSet(对象,'data.item.sub_item.bla.here.iam');//真的
我认为这是一个轻微的改进(成为单行):
这是因为&&运算符返回
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") )
//Just in case is not supported or not included by your framework
//***************************************************
Array.prototype.some = function(fn, thisObj) {
var scope = thisObj || window;
for ( var i=0, j=this.length; i < j; ++i ) {
if ( fn.call(scope, this[i], i, this) ) {
return true;
}
}
return false;
};
//****************************************************
function isSet (object, string) {
if (!object) return false;
var childs = string.split('.');
if (childs.length > 0 ) {
return !childs.some(function (item) {
if (item in object) {
object = object[item];
return false;
} else return true;
});
} else if (string in object) {
return true;
} else return false;
}
var object = {
data: {
item: {
sub_item: {
bla: {
here : {
iam: true
}
}
}
}
}
};
console.log(isSet(object,'data.item')); // true
console.log(isSet(object,'x')); // false
console.log(isSet(object,'data.sub_item')); // false
console.log(isSet(object,'data.item')); // true
console.log(isSet(object,'data.item.sub_item.bla.here.iam')); // true
alert( test.level1 && test.level1.level2 && test.level1.level2.level3 )
obj = {
"l1":"something",
"l2":[{k:0},{k:1}],
"l3":{
"subL":"hello"
}
}
if( obj._has( "something.['deep']['under'][1][0].item" ) ) {
//do something
}
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)
{
}
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")
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 );
}
var r1 = (((test || {}).level1 || {}).level2 || {}).level3;
var r2 = (((test || {}).level1 || {}).level2 || {}).foo;
var r1 = test.level1 && test.level1.level2 && test.level1.level2.level3;
var r2 = test.level1 && test.level1.level2 && test.level1.level2.foo;
function checkNested(obj) {
for (var i = 1; i < arguments.length; i++) {
if (!obj.hasOwnProperty(arguments[i])) {
return false;
}
obj = obj[arguments[i]];
}
return true;
}
function get_if_exist(str) {
try { return eval(str) }
catch(e) { return undefined }
}
function validChain( object, ...keys ) {
return keys.reduce( ( a, b ) => ( a || { } )[ b ], object ) !== undefined;
}
function objHasKeys(obj, keys) {
var next = keys.shift();
return obj[next] && (! keys.length || objHasKeys(obj[next], keys));
}
function nestedPropertyExists(obj, props) {
var prop = props.shift();
return prop === undefined ? true : obj.hasOwnProperty(prop) ? nestedPropertyExists(obj[prop], props) : false;
}
function deeptest(target, s){
s= s.split('.')
var obj= target[s.shift()];
while(obj && s.length) obj= obj[s.shift()];
return obj;
}
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);
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;
}
const propExists = (obj, path) => {
return !!path.split('.').reduce((obj, prop) => {
return obj && obj[prop] ? obj[prop] : undefined;
}, obj)
}
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'));
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