测试是否存在嵌套的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;i
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