创建一个 'object accessor' 函数 - 深度嵌套 javascript 个对象
Creating an 'object accessor' function - Deeply nested javascript objects
动机:给定一个深度嵌套的对象,在第N.However层有'currency'个键,N层可能不统一,这意味着对象A的货币键可能位于第4层,并且同一个键可能位于对象 B 的第 9 层
我想要实现的是创建一个统一的访问器。仅生成一次并在遇到类似对象数组(深度嵌套)时使用的即时访问器。
目前,通过递归,我设法将 'accessor path' 构造为字符串。
我如何将其应用于我的对象?
尝试这样做是否合理?我非常感谢您的输入、想法和意见。
// testObj[level][id][title][name][currency] === 'USD'
const testObj = {
level: {
id: {
title: {
name: {
currency: "USD"
}
}
}
}
}
// testObj2[a][b][c][currency]
const testObj2 = {
a: {
b: {
c: {
currency: "USD"
}
}
}
}
const testObj3 = {
a: {
b: {
c: {
d: {
e: {
currency: "USD"
}
}
}
}
}
}
const objectAccessCreator = (obj, targetKey, keysArray = []) => {
for (const [key, value] of Object.entries(obj)) {
if (key !== targetKey) {
keysArray.push(key);
if (typeof value !== 'object' || typeof value === null) {
return -1;
} else {
return objectAccessCreator(value, 'currency', keysArray);
}
}
if (key === targetKey) {
keysArray.push(key);
}
}
let accessChain = '';
for (const key of keysArray) {
accessChain += `[${key}]`;
}
return accessChain;
}
const targetKey = 'currency';
// [a][b][c][d][e][currency]
console.log(objectAccessCreator(testObj3, targetKey));
//[level][id][title][name][currency]
console.log(objectAccessCreator(testObj, targetKey));
//[a][b][c][currency]
console.log(objectAccessCreator(testObj2, targetKey));
您可以将字符串拆分为路径数组,然后使用 Array.reduce()
到 return 属性 值。
我将其包装在一个 getValue()
函数中,该函数接受一个对象和路径参数。
const objectAccessCreator = (obj, targetKey, keysArray = []) => {
for (const [key, value] of Object.entries(obj)) {
if (key !== targetKey) {
keysArray.push(key);
if (typeof value !== 'object' || typeof value === null) {
return -1;
} else {
return objectAccessCreator(value, 'currency', keysArray);
}
}
if (key === targetKey) {
keysArray.push(key);
}
}
let accessChain = '';
for (const key of keysArray) {
accessChain += `[${key}]`;
}
return accessChain;
}
const targetKey = 'currency';
function getValue(obj, path) {
return path.split(/[\[\]]+/).filter(s => s).reduce((obj, key) => {
return obj[key];
}, obj);
}
const testObjects = [
{ level: { id: { title: { name: { currency: "USD" } } } } },
{ a: { b: { c: { currency: "USD" } } } },
{ a: { b: { c: { d: { e: { currency: "USD" } } } } } }
];
for(let testObj of testObjects) {
const path = objectAccessCreator(testObj, targetKey);
console.log('Generated path:', path);
console.log('Value at path:', getValue(testObj, path));
}
.as-console-wrapper { max-height: 100% !important; }
我还建议使用“.”。路径分隔符,这在一定程度上简化了逻辑:
const objectAccessCreator = (obj, targetKey, keysArray = []) => {
for (const [key, value] of Object.entries(obj)) {
if (key !== targetKey) {
keysArray.push(key);
if (typeof value !== 'object' || typeof value === null) {
return -1;
} else {
return objectAccessCreator(value, 'currency', keysArray);
}
}
if (key === targetKey) {
keysArray.push(key);
}
}
return keysArray.join('.');
}
const targetKey = 'currency';
function getValue(obj, path) {
return path.split('.').reduce((obj, key) => {
return obj[key];
}, obj);
}
const testObjects = [
{ level: { id: { title: { name: { currency: "USD" } } } } },
{ a: { b: { c: { currency: "USD" } } } },
{ a: { b: { c: { d: { e: { currency: "USD" } } } } } }
];
for(let testObj of testObjects) {
const path = objectAccessCreator(testObj, targetKey);
console.log('Generated path:', path);
console.log('Value at path:', getValue(testObj, path));
}
.as-console-wrapper { max-height: 100% !important; }
以及直接从新的 getValue()
函数 return 获取 targetKey
值的示例:
const targetKey = 'currency';
function getValue(obj, property) {
for(let key in obj) {
if (obj[key] && (typeof(obj[key]) === 'object')) {
let value = getValue(obj[key], property);
if (value !== null) {
return value;
}
} else if (key === property) {
return obj[key];
}
}
return null;
}
const testObjects = [
{ level: { id: { title: { name: { currency: "USD" } } } } },
{ a: { b: { c: { currency: "USD" } } } },
{ a: { b: { c: { d: { e: { currency: "USD" } } } } } }
];
for(let testObj of testObjects) {
console.log(`Value of "${targetKey}":`, getValue(testObj, targetKey));
}
.as-console-wrapper { max-height: 100% !important; }
一种稍微简化的方法。 retrievePathAndValue
returns 路径及其在小对象中的值 ({path, value,}
)。如果您想稍后从结果路径中检索值,您可以使用 [result].path
和一些函数,例如所选答案中的函数或后者的 like this (see example。
const [ testObj, testObj2, testObj3 ] = testData();
const targetKey = 'currency';
console.log(retrievePathAndValue(testObj, targetKey));
console.log(retrievePathAndValue(testObj2, targetKey));
console.log(retrievePathAndValue(testObj3, targetKey));
function retrievePathAndValue(obj, key, path = ``) {
for (let k of Object.keys(obj)) {
if (obj[key]) {
return {
path: `${path}${path.length < 1 ? `` : `.`}${key}`,
value: obj[key],
};
}
if (obj[k] instanceof Object && !Array.isArray(obj[k])) {
return retrievePathAndValue(
obj[k],
key,
`${path}${path.length < 1 ? `` : `.`}${k}` );
}
}
return {
path: `[${key}] NOT FOUND`,
value: undefined,
};
}
function testData() {
const testObj = {
level: {
id: {
title: {
name: {
currency: "USD"
}
}
}
}
}
// testObj2[a][b][c][currency]
const testObj2 = {
a: {
b: {
c: {
currency: "USD"
}
}
}
}
const testObj3 = {
a: {
b: {
c: {
d: {
e: {
currency: "USD"
}
}
}
}
}
}
return [ testObj, testObj2, testObj3 ];
}
.as-console-wrapper {
max-height: 100% !important;
}
动机:给定一个深度嵌套的对象,在第N.However层有'currency'个键,N层可能不统一,这意味着对象A的货币键可能位于第4层,并且同一个键可能位于对象 B 的第 9 层
我想要实现的是创建一个统一的访问器。仅生成一次并在遇到类似对象数组(深度嵌套)时使用的即时访问器。
目前,通过递归,我设法将 'accessor path' 构造为字符串。 我如何将其应用于我的对象? 尝试这样做是否合理?我非常感谢您的输入、想法和意见。
// testObj[level][id][title][name][currency] === 'USD'
const testObj = {
level: {
id: {
title: {
name: {
currency: "USD"
}
}
}
}
}
// testObj2[a][b][c][currency]
const testObj2 = {
a: {
b: {
c: {
currency: "USD"
}
}
}
}
const testObj3 = {
a: {
b: {
c: {
d: {
e: {
currency: "USD"
}
}
}
}
}
}
const objectAccessCreator = (obj, targetKey, keysArray = []) => {
for (const [key, value] of Object.entries(obj)) {
if (key !== targetKey) {
keysArray.push(key);
if (typeof value !== 'object' || typeof value === null) {
return -1;
} else {
return objectAccessCreator(value, 'currency', keysArray);
}
}
if (key === targetKey) {
keysArray.push(key);
}
}
let accessChain = '';
for (const key of keysArray) {
accessChain += `[${key}]`;
}
return accessChain;
}
const targetKey = 'currency';
// [a][b][c][d][e][currency]
console.log(objectAccessCreator(testObj3, targetKey));
//[level][id][title][name][currency]
console.log(objectAccessCreator(testObj, targetKey));
//[a][b][c][currency]
console.log(objectAccessCreator(testObj2, targetKey));
您可以将字符串拆分为路径数组,然后使用 Array.reduce()
到 return 属性 值。
我将其包装在一个 getValue()
函数中,该函数接受一个对象和路径参数。
const objectAccessCreator = (obj, targetKey, keysArray = []) => {
for (const [key, value] of Object.entries(obj)) {
if (key !== targetKey) {
keysArray.push(key);
if (typeof value !== 'object' || typeof value === null) {
return -1;
} else {
return objectAccessCreator(value, 'currency', keysArray);
}
}
if (key === targetKey) {
keysArray.push(key);
}
}
let accessChain = '';
for (const key of keysArray) {
accessChain += `[${key}]`;
}
return accessChain;
}
const targetKey = 'currency';
function getValue(obj, path) {
return path.split(/[\[\]]+/).filter(s => s).reduce((obj, key) => {
return obj[key];
}, obj);
}
const testObjects = [
{ level: { id: { title: { name: { currency: "USD" } } } } },
{ a: { b: { c: { currency: "USD" } } } },
{ a: { b: { c: { d: { e: { currency: "USD" } } } } } }
];
for(let testObj of testObjects) {
const path = objectAccessCreator(testObj, targetKey);
console.log('Generated path:', path);
console.log('Value at path:', getValue(testObj, path));
}
.as-console-wrapper { max-height: 100% !important; }
我还建议使用“.”。路径分隔符,这在一定程度上简化了逻辑:
const objectAccessCreator = (obj, targetKey, keysArray = []) => {
for (const [key, value] of Object.entries(obj)) {
if (key !== targetKey) {
keysArray.push(key);
if (typeof value !== 'object' || typeof value === null) {
return -1;
} else {
return objectAccessCreator(value, 'currency', keysArray);
}
}
if (key === targetKey) {
keysArray.push(key);
}
}
return keysArray.join('.');
}
const targetKey = 'currency';
function getValue(obj, path) {
return path.split('.').reduce((obj, key) => {
return obj[key];
}, obj);
}
const testObjects = [
{ level: { id: { title: { name: { currency: "USD" } } } } },
{ a: { b: { c: { currency: "USD" } } } },
{ a: { b: { c: { d: { e: { currency: "USD" } } } } } }
];
for(let testObj of testObjects) {
const path = objectAccessCreator(testObj, targetKey);
console.log('Generated path:', path);
console.log('Value at path:', getValue(testObj, path));
}
.as-console-wrapper { max-height: 100% !important; }
以及直接从新的 getValue()
函数 return 获取 targetKey
值的示例:
const targetKey = 'currency';
function getValue(obj, property) {
for(let key in obj) {
if (obj[key] && (typeof(obj[key]) === 'object')) {
let value = getValue(obj[key], property);
if (value !== null) {
return value;
}
} else if (key === property) {
return obj[key];
}
}
return null;
}
const testObjects = [
{ level: { id: { title: { name: { currency: "USD" } } } } },
{ a: { b: { c: { currency: "USD" } } } },
{ a: { b: { c: { d: { e: { currency: "USD" } } } } } }
];
for(let testObj of testObjects) {
console.log(`Value of "${targetKey}":`, getValue(testObj, targetKey));
}
.as-console-wrapper { max-height: 100% !important; }
一种稍微简化的方法。 retrievePathAndValue
returns 路径及其在小对象中的值 ({path, value,}
)。如果您想稍后从结果路径中检索值,您可以使用 [result].path
和一些函数,例如所选答案中的函数或后者的 like this (see example。
const [ testObj, testObj2, testObj3 ] = testData();
const targetKey = 'currency';
console.log(retrievePathAndValue(testObj, targetKey));
console.log(retrievePathAndValue(testObj2, targetKey));
console.log(retrievePathAndValue(testObj3, targetKey));
function retrievePathAndValue(obj, key, path = ``) {
for (let k of Object.keys(obj)) {
if (obj[key]) {
return {
path: `${path}${path.length < 1 ? `` : `.`}${key}`,
value: obj[key],
};
}
if (obj[k] instanceof Object && !Array.isArray(obj[k])) {
return retrievePathAndValue(
obj[k],
key,
`${path}${path.length < 1 ? `` : `.`}${k}` );
}
}
return {
path: `[${key}] NOT FOUND`,
value: undefined,
};
}
function testData() {
const testObj = {
level: {
id: {
title: {
name: {
currency: "USD"
}
}
}
}
}
// testObj2[a][b][c][currency]
const testObj2 = {
a: {
b: {
c: {
currency: "USD"
}
}
}
}
const testObj3 = {
a: {
b: {
c: {
d: {
e: {
currency: "USD"
}
}
}
}
}
}
return [ testObj, testObj2, testObj3 ];
}
.as-console-wrapper {
max-height: 100% !important;
}