Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/371.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
测试是否存在嵌套的JavaScript对象键_Javascript_Object_Properties_Nested - Fatal编程技术网

测试是否存在嵌套的JavaScript对象键

测试是否存在嵌套的JavaScript对象键,javascript,object,properties,nested,Javascript,Object,Properties,Nested,如果我对某个对象有引用: var test = {}; 可能但不会立即具有嵌套对象,例如: {level1: {level2: {level3: "level3"}}}; 检查深度嵌套对象中是否存在属性的最佳方法是什么 3.1级;产量未定义,但alerttest.level1.level2.level3;失败了 我目前正在做这样的事情: if(test.level1 && test.level1.level2 && test.level1.level2.lev

如果我对某个对象有引用:

var test = {};
可能但不会立即具有嵌套对象,例如:

{level1: {level2: {level3: "level3"}}};
检查深度嵌套对象中是否存在属性的最佳方法是什么

3.1级;产量未定义,但alerttest.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

}

如果不希望出现TypeError,则必须一步一步地执行此操作,因为如果其中一个成员为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 || {};};
函数getNestedobj,…args{ 返回args.reduceobj,level=>obj&&obj[level],obj } 常量测试={level1:{level2:{level3:'level3'}}; console.loggetNestedtest,'level1','level2','level3';/'三级' console.loggetNestedtest,“level1”、“level2”、“level3”、“length”;//6. console.loggetNestedtest,“level1”、“level2”、“foo”;//未定义
console.loggetNestedtest,“a”,“b”;//未定义如果将名称处理为字符串:“t.level1.level2.level3”,则可以在任何深度读取对象属性

如果任何段未定义,则返回未定义。

以下是模式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;
    }

从一开始就详细阐述了以下选项。两者的树相同:

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 u2;。获取所有嵌套属性的获取需求

_.get(countries, 'greece.sparta.playwright')
先前的答复 用户可以享受其中有一个

获取路径 签名:u.getPathBj:Object,ks:String |数组

获取嵌套对象中任意深度处的值,该值基于 钥匙是给你的。键可以作为数组或点分隔字符串给出。 如果无法到达路径,则返回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
如果您在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
   alert( test.level1 && test.level1.level2 && test.level1.level2.level3 )

这是因为&&运算符返回它计算的最后一个操作数,并且它会短路。

如果属性存在,我正在寻找要返回的值,所以我在上面修改了CMS的答案。以下是我的想法:

函数getNestedPropertyobj,键{ //从键字符串获取属性数组 变量属性=键。拆分。; //遍历属性,如果对象为null或属性不存在,则返回未定义 对于变量i=0;igetNestedPropertytest,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

函数deeptestkeyPath,testObj{ var-obj; keyPath=keyPath.split'' var cKey=keyPath.shift; 函数getpObj,pKey{ 变量bracketStart,bracketEnd,o; bracketStart=pKey.indexOf[; 如果bracketStart>-1{//请检查嵌套数组 bracketEnd=pKey.indexOf]; var arrIndex=pKey.substrBractStart+1,bracketEnd-bracketStart-1; pKey=pKey.substr0,括号开始; var n=pObj[pKey]; o=n?n[arrIndex]:未定义; }否则{ o=pObj[pKey]; } 返回o; } obj=getestobj,cKey; 而obj&&keyPath.length{ obj=getobj,keyPath.shift; } 返回typeofobj!==“未定义”; } var obj={ l1:1级, arr1:[ {k:0}, {k:1}, {k:2} ], 分:{ a:a信, b:字母b } }; console.logl1:+deeptestl1,obj; console.logarr1[0]:+deeptestarr1[0],obj; console.logarr1[1].k:+deeptestarr1[1].k,obj; console.logarr1[1]。j:+deeptestarr1[1]。j,obj; console.logarr1[3]:+deeptestarr1[3],obj; console.logarr2:+deeptestarr2,obj 这适用于所有对象和数组:

例:

这是我对布赖恩答案的改进版本

我使用_has作为属性名,因为它可能与现有has属性ex:maps冲突

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(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);
我称之为悲伤小丑技巧,因为它使用的是符号o

编辑:

这是TypeScript的一个版本

它在编译时提供类型检查,如果使用VisualStudio之类的工具,还提供intellisense

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(o(test).level1).level2).level3, "none")
基于此,我使用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 );
}
我已经做了,谢谢你在对这个问题提出的一些建议中加入lodash,结果如下所示

免责声明1将字符串转换为引用是不必要的元编程,可能最好避免。不要忘记你的推荐信

免责声明2我们这里说的是每毫秒数百万次的操作。在大多数用例中,这些都不太可能产生很大的不同。选择最有意义的一个,了解每一个的局限性。对我来说,出于方便,我会选择像reduce这样的东西

–34%–最快

–45%

–50%

–54%

–63%

–69%

–72%

–86%

–100%–最慢

现在,我们还可以使用reduce循环嵌套键:

//@params o //@params path需要'obj.prop1.prop2.prop3' //返回:obj[path]值或“false”(如果道具不存在) const objPropIfExists=o=>path=>{ const levels=path.split'; const res=levels.length>0 ?级别。还原a,c=>a[c]| | 0,o :o[路径]; return!!res?res:false } 常量对象={ 姓名:'姓名', sys:{country:'AU'}, main:{temp:'34',temp_min:'13'}, 能见度:35% } const exists=objPropIfExistsobj'main.temp' const doesntExist=objPropIfExistsobj'main.temp.foo.bar.baz'
console.logexists,doesntExist我没有看到任何使用

所以我想出了自己的办法。 最棒的是你不需要插入字符串。实际上,您可以返回一个可链接的对象函数,并用它做一些神奇的事情。您甚至可以调用函数并获取数组索引来检查深层对象

函数解析目标{ var noop==>{}//我们使用一个noop函数,这样我们也可以调用方法 返回新的Proxynoop{ 盖特努普,钥匙{ //如果键为_result,则返回最终结果 返回键==='\u结果' 目标 :resolve//resolve with target value或undefined 目标===未定义?未定义:目标[键] }, //如果我们想测试一个函数,那么我们可以通过使用noop进行测试 //而不是在我们的代理中使用target applynoop,那,args{ 返回resolvetypeof target==“函数”?target.applythat,args:未定义 }, } } //已接受答案中的一些修改示例 var test={level1:{level2:=>{level3:'level3'}} var test1={key1:{key2:['item0']} //你需要在最后得到结果才能得到最终结果 console.logresolvetest.level1.level2.level3.\u结果 控制台.logresolvetest.level1.level2.level3.level4.level5.\u结果 console.logresolvetest1.key1.key2[0]。\u结果
console.logresolvetst1[0].key.\u result//don'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答案,彻底测试:
→参见您也可以将tc39可选链接方案与巴贝尔一起使用 7-

代码如下所示:

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);

我创建了一个小函数来安全地获取嵌套对象属性

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 flag的退路:

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要点:

还有一个非常紧凑的:

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
它不会执行得很好,因为它会拆分字符串,但会增加调用的可读性,并对所有内容进行迭代,即使很明显,除了增加函数本身的可读性之外,什么都找不到

至少比u.get

创建全局函数并在整个项目中使用要快

试试这个

函数isExistarg{ 试一试{ 返回arg; }抓住{ 返回false; } } 设obj={a:5,b:{c:5}; console.logisExist=>obj.b.c console.logisExist=>obj.b.foo
console.logisExist=>obj.test.foo您可能希望检查最近提出的一个与问题相关的问题,请参见此处的两个命题:如果level3属性为false,则当前方法可能存在问题,即使属性exist将返回nfalse看看这个示例,请简单地使用try-catch-also我不认为try/catch是测试对象是否存在的好方法:try/catch是用来处理异常的,而不是像这里的测试这样的正常情况。我认为在每一步中typeof foo==undefined更好,而且一般来说,如果您使用的是这种深度嵌套的属性,可能需要进行一些重构。此外,try/catch会导致Firebug中断,并且在任何浏览器中,如果抛出异常,则会打开“中断错误”。我对此投了赞成票,因为如果使用其他解决方案,浏览器将两次检查存在性。假设您想调用'a.c.b=2'。在修改值之前,浏览器必须检查是否存在,否则这将是操作系统捕获的内存错误。问题仍然存在:浏览器设置try-catch或调用hasOwnProperty n次的速度是否更快?为什么再次出现这种情况?在我看来,这是最干净的。我会说:如果您希望该属性存在,那么可以将其包装到try块中。如果它不存在,那就是一个错误。但是,如果您只是懒惰,并将常规代码放入catch块,以防属性不存在,try/catch被误用。这里需要一个if/else或类似的值。唯一的问题是如果存在多个级别的未定义键,则会出现一个类型错误,例如checkObjHasKeyTest、['level1','level2','asdf','asdf'];更合适的方法是every,它的值可以直接返回;返回false。一旦你知道它破裂,你就应该退出,一旦它为空或未定义,就不可能存在更深层次的东西。这将防止深层嵌套项上出现错误,因为它们显然也不存在。参数实际上不是数组。Array.prototype.slice.callarguments将其转换为正式数组。这将执行var obj=arguments[0];从var i=1开始,而不是复制参数objectI,为了节约起见,我用try/catch编写了一个版本,不出所料,除了在Safari中出于某种原因,性能非常糟糕。下面有一些答案非常有效,还有克劳迪乌的修改,也比选定的答案更有效。请参阅ES6中的jsperf,可以删除args变量声明,并且…args可以用作checkNested方法的第二个参数。这是一个非常难以维护的问题。如果任何属性键发生更改,项目中的所有开发人员都必须“字符串搜索”整个代码库。这并不是问题的真正解决方案,因为它引入了一个更大的问题problem@wared我认为最有趣的是它的简洁性。在链接的帖子中详细讨论了绩效特征。是的,它总是执行所有测试,但它避免创建临时变量,如果您想避免每次创建新的空对象的开销,可以将{}别名到变量。在99%的情况下,我不希望速度有问题,在速度有问题的情况下,没有什么可以替代分析。@MuhammadUmer不,测试| |{}的要点是,如果测试没有定义,那么你就在做{}.level1 |{}。当然,{}.level1是未定义的,所以这意味着你在做{}.level2,等等。@JoshuaTaylor:我想他的意思是,如果测试没有声明,就会出现引用错误,但这不是问题,因为如果没有声明,就会有一个bug需要修复,所以这个错误是一件好事。你说过,一旦习惯了它,就不难读懂了。这些都是你已经知道的迹象,这是一片混乱。那为什么要提出这个解决方案呢?它很容易出现打字错误,而且对可读性毫无帮助。看看它!如果我必须写一行难看的话,那应该是可读的;所以我要走了

要坚持使用iftest.level1&&test.level1.level2&&test.level1.level2.level3,除非我遗漏了什么,否则这对可能为false的布尔结束属性不起作用。。。悲哀地另外,我喜欢这个习惯用法。值得注意的是,这个方法非常有效,至少在Chrome中,在某些情况下优于@Claudiu修改版的selected answer。请参见此处的性能测试:Lodash确实需要一个u.isPathDefinedobj,pathString方法。@MatthewPayne这可能会很好,但实际上没有必要。你可以很容易地自己做这件事,函数是pathDefinedObject,path{return typeof uu.getPathobject,path!='undefined';}Lodash本身也有同样的功能:u.getcountries,'greece.sparta.PlaystWriter','default';/→ '默认“uu.hascountries,'希腊.斯巴特.剧作家”//→ 如果您需要确定多个不同的路径,那么最好考虑:var url=..gete,'currentTarget.myurl',null | | | | gete,'currentTarget.attributes.myurl.nodeValue',null | | nullI有点像这种带模板的方法,因为如果不设置,它将返回空字符串。我认为try-catch方法是最好的答案。查询对象的类型与假设API存在并在不存在的情况下相应失败之间有着本质上的区别。后者更适合于松散类型的语言。看见try-catch方法也比if-foo&&foo.bar&&foo.bar.baz&&foo.bar.baz.qux{…}清晰得多。我认为公平地说,这是一种灵感,让您的代码适应于°0o。我喜欢这个方法,因为它是诚实的,当您不知道对象类型时,它会在您面前抛出一个未定义的符号+1.只要你把这句话写在纸上,你也可以称之为“快乐小丑技巧”。我喜欢你的评论。这是一个非常好的视角——这种条件通常在ifs中使用,并且总是被外部括号包围。所以,是的,这确实是一个快乐的小丑:你真的需要爱上括号才能得到这一个…应该注意的是,测试的百分比越高,测试的速度越慢,那么lodash呢?明白吗?与这些答案相比,它的性能如何?根据具体情况,每种方法都比其他方法慢或快。如果找到所有键,则对象包裹可能最快,但如果未找到其中一个键,则本机解决方案/原始解决方案可能会更快。@eviriko如果未找到键,则任何方法的速度都会较慢,但与其他方法的速度成比例,仍然几乎相同。然而,你是对的——这更像是一种智力练习,而不是其他任何东西。我们这里说的是每毫秒一百万次迭代。我看不出有什么不同的用例。就我个人而言,为了方便起见,我会选择reduce或try/catch。与try{test.level1.level2.level3}catch e{//some logger e}相比,它的性能如何?{/如果有人感兴趣,我已经在这里发布了异步版本,这是我的最终方法函数validChain对象,路径{return path.split'。reducea,b=>a |{b],object!==undefined}请注意,这种语法几乎肯定会改变,因为一些TC39成员对此表示反对。但这可能会以某种形式及时提供,这是唯一重要的。。这是我在JS中最怀念的特性之一。我使您的测试失败,将平面道具的值设置为0。您必须关心类型强制。@germain为您工作吗?我显式地比较了不同falsys的===并添加了测试。如果你有更好的想法,请告诉我。我让你的测试再次失败,将平面道具的值设置为false。然后你可能想在你的对象中设置一个未定义的值,我知道这很奇怪,但它是JS。我将一个正负值设置为“未找到Prop”:const hasTruthyProp=Prop=>Prop===“未找到Prop”?false:true const path=obj=>path=>path.reduceobj,prop=>{return obj&&obj.hasOwnPropertyprop?obj[prop]:'prop not found'},obj const myFunc=composehasTruthyProp,pathbj你能把我的代码笔划在右上方,简单,正确并添加测试,然后把你的URL发给我吗?谢谢=跑向一个巨大的第三方图书馆。。。可能,但不是我喜欢的。效果很好。简单有效的创建代码。应该很简单。你照搬了他们通常说的话,并且想要避免。。。
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