使用动态计算的名称访问对象属性

2024-11-02 21:00:00
admin
原创
79
摘要:问题描述:我正在尝试使用动态名称访问对象的属性。这可能吗?const something = { bar: "Foobar!" }; const foo = 'bar'; something.foo; // The idea is to ...

问题描述:

我正在尝试使用动态名称访问对象的属性。这可能吗?

const something = { bar: "Foobar!" };
const foo = 'bar';
something.foo; // The idea is to access something.bar, getting "Foobar!"

解决方案 1:

有两种方法可以访问对象的属性:

  • 点符号:something.bar

  • 括号表示法:something['bar']

括号之间的值可以是任何表达式。因此,如果属性名称存储在变量中,则必须使用括号表示法:

var something = {
  bar: 'foo'
};
var foo = 'bar';

// both x = something[foo] and something[foo] = x work as expected
console.log(something[foo]);
console.log(something.bar)

运行代码片段Hide results展开片段

解决方案 2:

这是我的解决方案:

function resolve(path, obj) {
    return path.split('.').reduce(function(prev, curr) {
        return prev ? prev[curr] : null
    }, obj || self)
}

使用示例:

resolve("document.body.style.width")
// or
resolve("style.width", document.body)
// or even use array indexes
// (someObject has been defined in the question)
resolve("part.0.size", someObject) 
// returns null when intermediate properties are not defined:
resolve('properties.that.do.not.exist', {hello:'world'})

解决方案 3:

在 javascript 中我们可以使用以下方式访问:

  • 点符号 -foo.bar

  • 方括号 -foo[someVar]foo["string"]

但只有第二种情况允许动态访问属性:

var foo = { pName1 : 1, pName2 : [1, {foo : bar }, 3] , ...}

var name = "pName"
var num  = 1;

foo[name + num]; // 1

// -- 

var a = 2;
var b = 1;
var c = "foo";

foo[name + a][b][c]; // bar

解决方案 4:

下面是一个 ES6 示例,说明如何使用通过连接两个字符串动态生成的属性名称来访问对象的属性。

var suffix = " name";

var person = {
    ["first" + suffix]: "Nicholas",
    ["last" + suffix]: "Zakas"
};

console.log(person["first name"]);      // "Nicholas"
console.log(person["last name"]);       // "Zakas"

这称为计算属性名称

解决方案 5:

您可以通过多种不同方式实现这一点。

let foo = {
    bar: 'Hello World'
};

foo.bar;
foo['bar'];

括号符号特别强大,因为它可以让你访问基于变量的属性:

let foo = {
    bar: 'Hello World'
};

let prop = 'bar';

foo[prop];

这可以扩展到循环遍历对象的每个属性。由于较新的 JavaScript 结构(例如 for ... of ...),这看起来可能有些多余,但有助于说明一个用例:

let foo = {
    bar: 'Hello World',
    baz: 'How are you doing?',
    last: 'Quite alright'
};

for (let prop in foo.getOwnPropertyNames()) {
    console.log(foo[prop]);
}

对于嵌套对象,点和括号符号也都按预期工作:

let foo = {
    bar: {
        baz: 'Hello World'
    }
};

foo.bar.baz;
foo['bar']['baz'];
foo.bar['baz'];
foo['bar'].baz;

对象解构

我们还可以将对象解构视为访问对象属性的一种方式,但如下所示:

let foo = {
    bar: 'Hello World',
    baz: 'How are you doing?',
    last: 'Quite alright'
};

let prop = 'last';
let { bar, baz, [prop]: customName } = foo;

// bar = 'Hello World'
// baz = 'How are you doing?'
// customName = 'Quite alright'

解决方案 6:

你可以使用 Lodash get 这样做

_.get(object, 'a[0].b.c');

解决方案 7:

更新

使用 可以轻松访问对象中的根属性obj[variable],但嵌套会使事情变得复杂。为了不编写已写好的代码,我建议使用lodash.get

例子

// Accessing root property
var rootProp = 'rootPropert';
_.get(object, rootProp, defaultValue);

// Accessing nested property
var listOfNestedProperties = [var1, var2];
_.get(object, listOfNestedProperties);

Lodash get 可以以不同的方式使用,文档lodash.get

解决方案 8:

要动态访问属性,只需使用方括号 [],如下所示:

const something = { bar: "Foobar!" };
const userInput = 'bar';
console.log(something[userInput])

运行代码片段Hide results展开片段

问题

该解决方案中有一个重大问题!(我很惊讶其他答案还没有提出这个问题)。通常,您只想访问自己放置在该对象上的属性,而不想获取继承的属性。

以下是此问题的一个示例。这里有一个看似无害的程序,但它有一个不易察觉的错误 - 您能发现它吗?

const agesOfUsers = { sam: 16, sally: 22 }
const username = prompt('Enter a username:')
if (agesOfUsers[username] !== undefined) {
  console.log(`${username} is ${agesOfUsers[username]} years old`)
} else {
  console.log(`${username} is not found`)
}

运行代码片段Hide results展开片段

当提示输入用户名时,如果您提供“toString”作为用户名,它会显示以下消息:“toString is function toString() { [native code] } years old”。问题是它agesOfUsers是一个对象,因此会自动继承某些属性,例如.toString()从基类 Object 继承的属性。您可以在此处查看所有对象继承的属性的完整列表。

解决方案

  1. 改用Map 数据结构。Map 存储的内容不受原型问题的影响,因此它们为该问题提供了一个干净的解决方案。

const agesOfUsers = new Map()
agesOfUsers.set('sam', 16)
agesOfUsers.set('sally', 2)
console.log(agesOfUsers.get('sam')) // 16

  

运行代码片段Hide results展开片段

  1. 使用具有空原型的对象,而不是默认原型。您可以使用它Object.create(null)来创建这样的对象。这种对象不会受到这些原型问题的影响,因为您已明确创建了它,使其不继承任何内容。

const agesOfUsers = Object.create(null)
agesOfUsers.sam = 16
agesOfUsers.sally = 22;
console.log(agesOfUsers['sam']) // 16
console.log(agesOfUsers['toString']) // undefined - toString was not inherited

  

运行代码片段Hide results展开片段

  1. 您可以首先使用Object.hasOwn(yourObj, attrName)来检查您想要访问的动态键是否直接在对象上而不是继承的(在此处了解更多信息)。这是一个相对较新的功能,因此在将其放入代码之前请检查兼容性表。在Object.hasOwn(yourObj, attrName)出现之前,您可以通过 实现相同的效果Object.prototype.hasOwnProperty.call(yourObj, attrName)。有时,您可能会看到使用的代码yourObj.hasOwnProperty(attrName),有时它可以工作,但它有一些陷阱,您可以在此处阅读。

// Try entering the property name "toString",
// you'll see it gets handled correctly.
const user = { name: 'sam', age: 16 }
const propName = prompt('Enter a property name:')
if (Object.hasOwn(user, propName)) {
  console.log(`${propName} = ${user[propName]}`)
} else {
  console.log(`${propName} is not found`)
}

运行代码片段Hide results展开片段

  1. 如果您知道您尝试使用的密钥永远不会是继承属性的名称(例如,它们可能是数字,或者它们都具有相同的前缀等),那么您可以选择使用原始解决方案。

解决方案 9:

我遇到过一种情况,我认为我想将对象属性的“地址”作为数据传递给另一个函数并填充对象(使用 AJAX),从地址数组中进行查找,然后显示在另一个函数中。如果不进行字符串杂技,我就无法使用点符号,所以我认为传递数组可能更好。我最终还是做了一些不同的事情,但似乎与这篇文章有关。

下面是我想要获取数据的语言文件对象的示例:

const locs = {
  "audioPlayer": {
    "controls": {
      "start": "start",
      "stop": "stop"
    },
    "heading": "Use controls to start and stop audio."
  }
}

我希望能够传递一个数组,例如:[“audioPlayer”、“controls”、“stop”] 来访问语言文本,在本例中为“stop”。

我创建了这个小函数,它查找“最不具体”(第一个)地址参数,并将返回的对象重新分配给自身。然后,它就可以查找下一个最具体的地址参数(如果存在)。

function getText(selectionArray, obj) {
  selectionArray.forEach(key => {
    obj = obj[key];
  });
  return obj;
}

用法:

/* returns 'stop' */
console.log(getText(["audioPlayer", "controls", "stop"], locs)); 

/* returns 'use controls to start and stop audio.' */
console.log(getText(["audioPlayer", "heading"], locs)); 

解决方案 10:

ES5 // 检查深度嵌套变量

这段简单的代码可以检查深度嵌套的变量/值是否存在,而不必检查每个变量......

var getValue = function( s, context ){
    return Function.call( context || null, 'return ' + s )();
}

例如-深度嵌套的对象数组:

a = [ 
    {
      b : [
          {
             a : 1,
             b : [
                 {
                    c : 1,
                    d : 2   // we want to check for this
                 }
             ]
           }
      ]
    } 
]

而不是:

if(a && a[0] && a[0].b && a[0].b[0] && a[0].b[0].b && a[0].b[0].b[0] && a[0].b[0].b[0].d && a[0].b[0].b[0].d == 2 )  // true

我们现在可以:

if( getValue('a[0].b[0].b[0].d') == 2 ) // true

干杯!

解决方案 11:

其他人已经提到了“点”和“方”语法,所以我想以类似的方式介绍访问函数和发送参数。

代码 jsfiddle

var obj = {method:function(p1,p2,p3){console.log("method:",arguments)}}

var str = "method('p1', 'p2', 'p3');"

var match = str.match(/^s*(S+)((.*));s*$/);

var func = match[1]
var parameters = match[2].split(',');
for(var i = 0; i < parameters.length; ++i) {
  // clean up param begninning
    parameters[i] = parameters[i].replace(/^s*['"]?/,'');
  // clean up param end
  parameters[i] = parameters[i].replace(/['"]?s*$/,'');
}

obj[func](parameters); // sends parameters as array
obj[func].apply(this, parameters); // sends parameters as individual values

解决方案 12:

演示对象示例

let obj = {
    name: {
        first_name: "Bugs",
        last_name: "Founder",
        role: "Programmer"
    }
}

用于获取值的点字符串键

let key = "name.first_name"

功能

const getValueByDottedKeys = (obj, strKey)=>{
    let keys = strKey.split(".")
    let value = obj[keys[0]];   
    for(let i=1;i<keys.length;i++){
        value = value[keys[i]]
    }
    return value
}

调用 getValueByDottedKeys 函数

value = getValueByDottedKeys(obj, key)
console.log(value)

输出

Bugs
const getValueByDottedKeys = (obj, strKey)=>{
    let keys = strKey.split(".")
    let value = obj[keys[0]];   
    for(let i=1;i<keys.length;i++){
        value = value[keys[i]]
    }
    return value
}

let obj = {
    name: {
        first_name: "Bugs",
        last_name: "Founder",
        role: "Programmer"
    }
}

let key = "name.first_name"

value = getValueByDottedKeys(obj, key)
console.log(value)

运行代码片段Hide results展开片段

解决方案 13:

不久前,我问了一个与该主题有点重复的问题,经过大量研究后,发现这里缺少很多应该存在的信息,我觉得我有一些有价值的内容可以添加到这个旧帖子中。

  • 首先我想说的是,有几种方法可以获取属性的值并将其存储在动态变量中。在我看来,最流行、最简单的方法是:

let properyValue = element.style['enter-a-property'];

但是我很少采用这种方法,因为它不适用于通过样式表分配的属性值。为了给您举个例子,我将用一些伪代码进行演示。

 let elem = document.getElementById('someDiv');
 let cssProp = elem.style['width'];

使用上面的代码示例;如果存储在“elem”变量中的 div 元素的 width 属性在 CSS 样式表中设置了样式,而不是在其 HTML 标记内设置了样式,那么您无疑会得到存储在 cssProp 变量中的未定义的返回值。出现未定义值的原因是,为了获得正确的值,需要计算 CSS 样式表中编写的代码才能获得该值,因此;您必须使用一种方法来计算样式表中的属性值。

  • 从今以后使用 getComputedStyle() 方法!

function getCssProp(){
  let ele = document.getElementById("test");
  let cssProp = window.getComputedStyle(ele,null).getPropertyValue("width");
}

W3Schools getComputedValue Doc这给出了一个很好的例子,让你可以试着使用它,但是,这个链接Mozilla CSS getComputedValue doc详细讨论了 getComputedValue 函数,任何对这个主题不完全清楚的有抱负的开发人员都应该阅读它。

  • 顺便提一下,getComputedValue 方法只能获取,不能设置。这显然是一个重大缺点,但是有一种方法可以从 CSS 样式表中获取值,也可以设置值,尽管它不是标准的 Javascript。JQuery 方法...

$(selector).css(property,value)

...确实获取了,也确实设置了。这是我使用的,唯一的缺点是你必须了解 JQuery,但说实话,这是每个 JavaScript 开发人员都应该学习 JQuery 的众多好理由之一,它让生活变得轻松,并提供标准 Javascript 所没有的方法(例如这个)。希望这对某人有帮助!!!

解决方案 14:

对于任何想要设置嵌套变量值的人来说,以下是操作方法:

const _ = require('lodash'); //import lodash module

var object = { 'a': [{ 'b': { 'c': 3 } }] };

_.set(object, 'a[0].b.c', 4);
console.log(object.a[0].b.c);
// => 4

文档:https ://lodash.com/docs/4.17.15#set

此外,如果您想获取一个值,请参阅文档: https: //lodash.com/docs/4.17.15#get

解决方案 15:

您可以使用括号符号动态访问对象的属性。这看起来像这样obj[yourKey] ,但是 JavaScript 对象实际上并非设计为动态更新或读取。它们旨在在初始化时定义

如果您想动态分配和访问key value对,您应该使用地图。

const yourKey = 'yourKey';

// initialise it with the value
const map1 = new Map([
  ['yourKey', 'yourValue']
]);

// initialise empty then dynamically assign
const map2 = new Map();
map2.set(yourKey, 'yourValue');

console.log(map1.get(yourKey));
console.log(map2.get(yourKey));

运行代码片段Hide results展开片段

解决方案 16:

我遇到了同样的问题,但是 lodash 模块在处理嵌套属性时受到限制。我按照递归后代解析器的思想编写了一个更通用的解决方案。此解决方案可在以下 Gist 中找到:

递归下降对象取消引用

解决方案 17:

这是动态访问对象属性的一种方法,案例是基于 localstorage 数据访问 JSON 对象 {preferredIndustry= foodItemsFeatured}

data.foodItemsFeatured 可供访问

在此处输入图片描述

let storageData = this.data; // JSON Response
let preferredData = localStorage.getItem('preferredIndustry'); //foodItemsFeatured

/* Dynamically access Object's property */
this.preferredFeaturedItems = this.data[preferredData as keyof typeof storageData];

解决方案 18:

如果您想避免使用 ES6 {[prop]:val} 方法并能够在箭头函数中使用它:

var obj = {a:1}, prop = "b", val = 2;
console.log(JSON.stringify(obj)); // {"a":1}
Object.defineProperty(obj, prop, {value:val, writable:true,enumerable:true,configurable:true});
console.log(JSON.stringify(obj)); // {"a":1,"b":2};

箭头函数:

var set = (obj, prop, val) => Object.defineProperty(obj, prop, {value:val, writable:true,enumerable:true,configurable:true});
set(obj, "c", 3);
console.log(JSON.stringify(obj));// {"a":1,"b":2, "c":3};

解决方案 19:

我使用下面的解决方案。它似乎比reduce函数更容易阅读。

它使用括号表示法来获取属性值。它支持通过提供点(“.”)分隔的键来获取嵌套对象的属性值。如果提供的键中的属性在对象中不存在,则返回 undefined。这是通过使用安全链运算符“?”实现的。

function getPropertyValue(object, key) {
  key.split(".").forEach(token => object = object?.[token]);
  return object;
}

// Examples
const o = { a: 1, b: { c: 2, d: 3 } };
console.log(getPropertyValue(o, "a"));
console.log(getPropertyValue(o, "b"));
console.log(getPropertyValue(o, "b.c"));

// Examples where properties does not exist
console.log(getPropertyValue(o, "d"));
console.log(getPropertyValue(o, "b.a"));
console.log(getPropertyValue(o, "d.c"));
console.log(getPropertyValue(o, "b.c.d"));

运行代码片段Hide results展开片段

解决方案 20:

通过引用查找对象(不带字符串),注意确保传入的对象是克隆的,我使用 lodash 中的 cloneDeep

如果物体看起来像

const obj = {data: ['an Object',{person: {name: {first:'nick', last:'gray'} }]

路径看起来像

const objectPath = ['data',1,'person',name','last']

然后调用下面的方法,它将按给定的路径返回子对象

const child = findObjectByPath(obj, objectPath)
alert( child) // alerts "last"


const findObjectByPath = (objectIn: any, path: any[]) => {
    let obj = objectIn
    for (let i = 0; i <= path.length - 1; i++) {
        const item = path[i]
        // keep going up to the next parent
        obj = obj[item] // this is by reference
    }
    return obj
}

解决方案 21:

getter您可以在 Javascript 中使用

getter 文档

检查对象内部是否存在相关属性,如果不存在,则从窗口中获取

const something = {
    get: (n) => this.n || something.n || window[n]
};

解决方案 22:

您应该使用JSON.parse,请查看https://www.w3schools.com/js/js_json_parse.asp

const obj = JSON.parse('{ "name":"John", "age":30, "city":"New York"}')
console.log(obj.name)
console.log(obj.age)
相关推荐
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   681  
  在项目管理领域,集成产品开发(IPD)流程以其高效、协同的特点,被众多企业视为提升产品竞争力的关键。IPD流程强调跨部门、跨职能的紧密合作,以确保产品从概念到市场各个环节的无缝衔接。然而,实现这一目标并非易事,它需要企业深刻理解并掌握IPD流程中的跨部门协作艺术。本文将深入探讨IPD流程中跨部门协作的三个关键点,旨在为...
IPD项目管理咨询   9  
  掌握IPD流程图:提升团队协作的关键路径在当今快速变化的商业环境中,团队协作的效率与效果直接关系到项目的成功与否。集成产品开发(Integrated Product Development,简称IPD)作为一种先进的研发管理理念,通过跨部门、跨领域的协同工作,能够显著提升产品开发的速度与质量。而IPD流程图,则是这一理...
IPD流程阶段   9  
  IPD流程概述:理解其核心价值与实施背景集成产品开发(Integrated Product Development,简称IPD)是一种先进的产品开发管理理念,它强调跨部门协作、市场导向和快速响应变化的能力。IPD流程不仅关注产品本身的技术创新,更注重将市场、研发、生产、销售等各个环节紧密集成,以实现产品从概念到市场的高...
华为IPD是什么   7  
  在项目管理领域,IPD(Integrated Product Development,集成产品开发)流程以其跨部门协作、高效决策和快速响应市场变化的特点,被众多企业视为提升竞争力的关键。然而,实践IPD流程并非易事,项目管理中的种种错误往往阻碍了其效果的充分发挥。本文旨在深入探讨如何在实施IPD流程时避免这些常见错误,...
IPD框架   7  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用