检查关联数组中一个键是否存在

4
告诉我,如何正确地检查关联数组中的键是否存在?
例如:
var mydata = {
    key1: '',
    key2: {
        subkey1: {
            subkey1_1: {
                value1: ''
                value2" '',
            },
        },
        subkey2: '';
    },
}

if ((mydata.key2 != undefined) && (mydata.key2.subkey1 != undefined) && (mydata.key2.subkey1.subkey1_1 != undefined))
    mydata.key2.subkey1.subkey1_1.value1 = 'test';

过长且令人困惑

((mydata.key2 != undefined) && (mydata.key2.subkey1 != undefined) && (mydata.key2.subkey1.subkey1_1 != undefined))

我希望使用一个更简单的函数,比如

safeSet(mydata.key2.subkey1.subkey1_1.value1, 'test');

或者

if (is_undefined(mydata.key2.subkey1.subkey1_1.value1) == true)
    mydata.key2.subkey1.subkey1_1.value1 = 'test'; // now - error if 'mydata.key2.subkey1.subkey1_1' not exist

3
"associative arrays"? 你的意思是 "对象" 吗? - Jaromanda X
你想要检查键是否存在,还是键是否有值?你的问题说的是前者,但你的代码暗示了后者。无论哪种方式,听起来你可以使用 try/catch 块。 - Rory McCrossan
7个回答

2

您可以使用reduce()创建自定义函数来测试嵌套属性是否存在。您只需将键作为字符串传递即可。

var mydata = {
  key1: '',
  key2: {
    subkey1: {
      subkey1_1: {
        value1: '',
        value2: '',
      },
    },
    subkey2: ''
  },
}

function safeSet(key, data) {
  return key.split('.').reduce(function(r, e) {
    return r ? r[e] : undefined;
  }, data) != undefined
}

console.log(safeSet('key2.subkey1.subkey1_1.value1', mydata))


1

1
如果您要查找的键位于多个层次深度,那么 obj.hasOwnProperty("key") 有什么用处? - Rory McCrossan

1

或者,您可以利用Lodash.has()方法。 然后,您只需要检查:

if (_.has(mydata, 'key2.subkey1.subkey1_1.value1')
    mydata.key2.subkey1.subkey1_1.value1 = 'test';

0
你可以分割路径并检查接下来的元素是否存在。如果不存在,则将对象分配给新属性。
然后返回该属性的值。
最后分配该值。

function setValue(object, path, value) {
    var fullPath = path.split('.'),
        way = fullPath.slice(),
        last = way.pop();

    way.reduce(function (r, a) {
        return r[a] = r[a] || {};
    }, object)[last] = value;
}

var object = { key1: '', key2: { subkey1: { subkey1_1: { value1: '', value2: '' } }, subkey2: '' } };

setValue(object, 'key2.subkey1.subkey1_1.value1', 'test');
console.log(object);


0

如果想要在嵌套结构中获取某些内容,我会这样做:

function getPath(element, path) {
    var handledSoFar = [];
    for (var i = 0; i < path.length; i++) {
        var property = path[i];
        handledSoFar.push(property);
        if (typeof element[property] === 'undefined') {
            throw new Error('Path ' + handledSoFar.join('->') + ' is undefined');
        }
        element = object[property];
    }
    return element;
}

var mydata = {
    key1: '',
    key2: {
        subkey1: {
            subkey1_1: {
                value1: '',
                value2: 'hi'
            }
        },
        subkey2: ''
    }
};

// Prints 'hi'
console.log(getPath(mydata, ['key2', 'subkey1', 'subkey1_1', 'value2']));

// Throws error 'Path key2->subkey2->subkey1_1 is undefined'
console.log(getPath(mydata, ['key2', 'subkey1', 'subkey1_1', 'value2']));

当然,在 handledSoFar 中跟踪搜索是可选的,但对于开发/调试可能很有用。

0

您还可以使用 lodash 深度字段选择器:lodash.get (文档)

const get = require('lodash.get');
const set = require('lodash.set');

if (!get(mydata, 'key2.subkey1.subkey1_1.value1')) {
    set(mydata, 'key2.subkey1.subkey1_1.value1', 'test');
}

0
你提出的示例函数存在问题:
safeSet(mydata.key2.subkey1.subkey1_1.value1, 'test');

或者

is_undefined(mydata.key2.subkey1.subkey1_1.value1)

这里的 mydata.key2.subkey1... 部分是在函数被调用之前运行的。因此,如果其中一个子键不存在,异常将在您的代码到达之前抛出。

不过,您可以使用回调函数来实现类似的功能...

safeSet(function(val) { mydata.key2.subkey1.subkey1_1.value1 = val; }, 'test')

safeSet的实现将会是:

var safeSet = function(setterFunc, val) {
  try {
    setterFunc(val);
  } catch (e) {
    if (e instanceof TypeError) {
      return false;
    } else {
      throw e;
    }
  }
  return true;
}

safeSet函数返回true,如果值被设置了,则返回false。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接