javascript JS 对象具有属性深度检查
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/33444711/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
JS object has property deep check
提问by BadVolt
Let's say we have JS object:
假设我们有一个 JS 对象:
var object = {
innerObject:{
deepObject:{
value:'Here am I'
}
}
};
How can we check if value
property exists?
I can see only two ways:
我们如何检查value
属性是否存在?我只能看到两种方式:
First one:
第一:
if(object && object.innerObject && object.innerObject.deepObject && object.innerObject.deepObject.value) {
console.log('We found it!');
}
Second one:
第二个:
if(object.hasOwnProperty('innerObject') && object.innerObject.hasOwnProperty('deepObject') && object.innerObject.deepObject.hasOwnProperty('value')) {
console.log('We found it too!');
}
But is there a way to do a deep check? Let's say, something like:
但是有没有办法进行深度检查?比方说,像这样:
object['innerObject.deepObject.value']
or
或者
object.hasOwnProperty('innerObject.deepObject.value')
回答by Viktor Bahtev
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');
回答by nem035
You could make a recursive method to do this.
您可以使用递归方法来执行此操作。
The method would iterate (recursively) on all 'object' properties of the object you pass in and return true
as soon as it finds one that contains the property you pass in. If no object contains such property, it returns false
.
该方法将迭代(递归)您传入的对象的所有“对象”属性,并在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
回答by wintvelt
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.
替代递归函数:循环遍历所有对象键,对于任何键,它检查它是否是一个对象,如果是,则递归调用自身。否则,对于名称为 的任何键,返回包含真、假、假的数组propName
。在.reduce
随后通过或语句卷起阵列。
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.'
PS:@nem 的回答显示了它如何能够提高性能:他的解决方案在第一个找到的“值”时中断。
回答by mehmatrix
My Approach would be using try/catch blocks. Because i don't like to pass deep property paths in strings. I'm a lazy guy who likes autocompletion :)
我的方法是使用 try/catch 块。因为我不喜欢在字符串中传递深层属性路径。我是一个喜欢自动完成的懒人:)
Javascript objects are evaluated on runtime. So if you return your object statement in a callback function, that statement is not going to be evaluated until callback function is invoked.
Javascript 对象在运行时进行评估。因此,如果您在回调函数中返回对象语句,则在调用回调函数之前不会评估该语句。
So this function just wraps the callback function inside a try catch statement. If it catches the exception returns false.
所以这个函数只是将回调函数包装在一个 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
}
When it comes to performance, it's hard to say which approach is better. On my tests if the object properties exist and the statement is successful I noticed using try/catch can be 2x 3x times faster than spliting string to keys and checking if keys exist in the object.
说到性能,很难说哪种方法更好。在我的测试中,如果对象属性存在并且语句成功,我注意到使用 try/catch 可以比将字符串拆分为键并检查对象中是否存在键快 2 倍 3 倍。
But if the property doesn't exist at some point, prototype approach returns the result almost 7x times faster.
但是如果属性在某个时候不存在,原型方法返回结果的速度几乎是 7 倍。
See the test yourself: https://jsfiddle.net/yatki/382qoy13/2/
自己看测试:https: //jsfiddle.net/yatki/382qoy13/2/
You can also check the library I wrote here: https://github.com/yatki/try-to-validate
你也可以查看我在这里写的库:https: //github.com/yatki/try-to-validate
回答by Riccardo Cassano
Try this nice and easy solution :
试试这个简单易用的解决方案:
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;
}
回答by Rolf
In case you are writing JavaScript for Node, then there is an assert module with a 'deepEqual' method
如果您正在为 Node 编写 JavaScript,那么有一个带有“deepEqual”方法的assert 模块
const assert = require('assert');
assert.deepEqual(testedObject, {
innerObject:{
deepObject:{
value:'Here am I'
}
}
});
回答by DanielK
I use Try-Catch
我使用 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);
回答by Mark Baaijens
I have created a very simple function for this using the recursive and happy flow coding strategy. Also nice to add it to the Object.prototype (with enumerate:false!!) in order to have it available for all objects.
我使用递归和快乐流编码策略为此创建了一个非常简单的函数。也很高兴将它添加到 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
});