假设我们有JS对象:
var object = {
innerObject:{
deepObject:{
value:'Here am I'
}
}
};
我们如何检查value
属性是否存在?
我只能看到两种方式:
第一个:
if(object && object.innerObject && object.innerObject.deepObject && object.innerObject.deepObject.value) {
console.log('We found it!');
}
第二个:
if(object.hasOwnProperty('innerObject') && object.innerObject.hasOwnProperty('deepObject') && object.innerObject.deepObject.hasOwnProperty('value')) {
console.log('We found it too!');
}
但有没有办法进行深入检查?让我们说,像:
object['innerObject.deepObject.value']
或
object.hasOwnProperty('innerObject.deepObject.value')
答案 0 :(得分:16)
There isn't a built-in way for this kind of check but you can implement it easily. Create a function, pass a string representing the property path, split the path by .
and iterate over this path:
Object.prototype.hasOwnNestedProperty = function(propertyPath){
if(!propertyPath)
return false;
var properties = propertyPath.split('.');
var obj = this;
for (var i = 0; i < properties.length; i++) {
var prop = properties[i];
if(!obj || !obj.hasOwnProperty(prop)){
return false;
} else {
obj = obj[prop];
}
}
return true;
};
// Usage:
var obj = {
innerObject:{
deepObject:{
value:'Here am I'
}
}
}
obj.hasOwnNestedProperty('innerObject.deepObject.value');
答案 1 :(得分:11)
您可以使用递归方法来执行此操作。
该方法将迭代(递归地)所有对象&#39;您传入的对象的属性,并在找到包含您传入的属性的对象后立即返回true
。如果没有对象包含此类属性,则返回false
。
var obj = {
innerObject: {
deepObject: {
value: 'Here am I'
}
}
};
function hasOwnDeepProperty(obj, prop) {
if (typeof obj === 'object' && obj !== null) { // only performs property checks on objects (taking care of the corner case for null as well)
if (obj.hasOwnProperty(prop)) { // if this object already contains the property, we are done
return true;
}
for (var p in obj) { // otherwise iterate on all the properties of this object
if (obj.hasOwnProperty(p) && // and as soon as you find the property you are looking for, return true
hasOwnDeepProperty(obj[p], prop)) {
return true;
}
}
}
return false;
}
console.log(hasOwnDeepProperty(obj, 'value')); // true
console.log(hasOwnDeepProperty(obj, 'another')); // false
&#13;
答案 2 :(得分:3)
Alternative recursive function:
Loops over all object keys, for any key it checks if it is an object, and if so, calls itself recursively.
Otherwise, returns array with true, false, false for any key with the name propName
.
The .reduce
then rolls up array through an or statement.
function deepCheck(obj,propName) {
if obj.hasOwnProperty(propName) { // performance improvement (thanks to @nem's solution)
return true;
}
return Object.keys(obj) // turns keys of object into array of strings
.map(prop => { // loop over the array
if (typeof obj[prop] == 'object') { // if property is object
return deepCheck(obj[prop],propName); // call recursively
} else {
return (prop == propName); // return true or false
}
}) // result is array like [false, false, true, false]
.reduce(function(previousValue, currentValue, index, array) {
return previousValue || currentValue;
} // do an or, or comparison of everything in array
// returns true if at least one value is true
)
}
deepCheck(object,'value'); // === true
PS: @nem's answer showed how it could be more performant: his solution breaks off at the first found 'value.'
答案 3 :(得分:0)
我的方法将使用try / catch块。因为我不喜欢在字符串中传递深层属性路径。我是一个喜欢自动完成的懒人:)
在运行时评估Javascript对象。因此,如果在回调函数中返回对象语句,则在调用回调函数之前不会评估该语句。
所以这个函数只是将回调函数包装在try catch语句中。如果它捕获异常则返回false。
var obj = {
innerObject: {
deepObject: {
value: 'Here am I'
}
}
};
const validate = (cb) => {
try {
return cb();
} catch (e) {
return false;
}
}
if (validate(() => obj.innerObject.deepObject.value)) {
// gonna work
}
if (validate(() => obj.x.y.z)) {
// not gonna work
}
在性能方面,很难说哪种方法更好。 在我的测试中,如果对象属性存在且语句成功,我注意到使用try / catch可以比将字符串拆分为键并检查对象中是否存在键快2倍3倍。
但如果该属性在某些时候不存在,那么原型方法的结果几乎要快7倍。
自己查看测试:https://jsfiddle.net/yatki/382qoy13/2/
您还可以查看我在此处写的库:https://github.com/yatki/try-to-validate
答案 4 :(得分:0)
尝试这个简单易用的解决方案:
public hasOwnDeepProperty(obj, path)
{
for (var i = 0, path = path.split('.'), len = path.length; i < len; i++)
{
obj = obj[path[i]];
if (!obj) return false;
};
return true;
}
答案 5 :(得分:0)
如果您正在为Node编写JavaScript,则会有assert module with a 'deepEqual' method
const assert = require('assert');
assert.deepEqual(testedObject, {
innerObject:{
deepObject:{
value:'Here am I'
}
}
});
答案 6 :(得分:0)
我使用Try-Catch
var object = {
innerObject:{
deepObject:{
value:'Here am I'
}
}
};
var object2 = {
a: 10
}
let exist = false, exist2 = false;
try {
exist = !!object.innerObject.deepObject.value
exist2= !!object2.innerObject.deepObject.value
} catch(e) {
}
console.log(exist);
console.log(exist2);
答案 7 :(得分:0)
我使用递归和快乐的流编码策略为此创建了一个非常简单的函数。最好将其添加到Object.prototype(带有enumerate:false !!)中,以使其可用于所有对象。
function objectHasOwnNestedProperty(obj, keys)
{
if (!obj || typeof obj !== 'object')
{
return false;
}
if(typeof keys === 'string')
{
keys = keys.split('.');
}
if(!Array.isArray(keys))
{
return false;
}
if(keys.length == 0)
{
return Object.keys(obj).length > 0;
}
var first_key = keys.shift();
if(!obj.hasOwnProperty(first_key))
{
return false;
}
if(keys.length == 0)
{
return true;
}
return objectHasOwnNestedProperty(obj[first_key],keys);
}
Object.defineProperty(Object.prototype, 'hasOwnNestedProperty',
{
value: function () { return objectHasOwnNestedProperty(this, ...arguments); },
enumerable: false
});