[英]Object has-property-deep check in JavaScript
假設我們有這個 JavaScript 對象:
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')
這種檢查沒有內置方法,但您可以輕松實現。 創建一個函數,傳遞一個表示屬性路徑的字符串,將路徑拆分為.
,並遍歷此路徑:
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' } } } console.log(obj.hasOwnNestedProperty('innerObject.deepObject.value'));
您可以使用遞歸方法來執行此操作。
您在傳遞和返回對象的所有“對象”特性的方法將迭代(遞歸) 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
替代遞歸函數:
循環遍歷所有對象鍵。 對於任何鍵,它檢查它是否是一個對象,如果是,則遞歸調用自身。
否則,它會為名稱為propName
任何鍵返回一個包含 true、false、false 的數組。
.reduce
然后通過or語句匯總數組。
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
}
}) // The result is an array like [false, false, true, false]
.reduce(function(previousValue, currentValue, index, array) {
return previousValue || currentValue;
} // Do an 'or', or comparison of everything in the array.
// It returns true if at least one value is true.
)
}
deepCheck(object,'value'); // === true
PS: nem035 的回答顯示了它如何能夠提高性能:他的解決方案在第一個找到的“值”處中斷。
我的方法是使用 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)) { // Is going to work } if (validate(() => obj.xyz)) { // Is not going to work }
說到性能,很難說哪種方法更好。 在我的測試中,如果對象屬性存在並且語句成功,我注意到使用 try/catch 可以比將字符串拆分為鍵並檢查對象中是否存在鍵快 2 倍 3 倍。
但是如果屬性在某個時候不存在,原型方法返回結果的速度幾乎是 7 倍。
自己看測試: https : //jsfiddle.net/yatki/382qoy13/2/
你也可以查看我在這里寫的庫: https : //github.com/yatki/try-to-validate
我使用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);
試試這個簡單易用的解決方案:
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;
}
如果您正在為 Node.js 編寫 JavaScript,那么有一個帶有“deepEqual”方法的assert 模塊:
const assert = require('assert');
assert.deepEqual(testedObject, {
innerObject:{
deepObject:{
value:'Here am I'
}
}
});
我使用遞歸和快樂流編碼策略為此創建了一個非常簡單的函數。 將它添加到 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
});
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.