使用变量动态访问对象属性

时间:2010-11-22 11:23:32

标签: javascript object properties

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

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

18 个答案:

答案 0 :(得分:779)

对象有two ways to access properties

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

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

var foo = 'bar';
something[foo];
// both x = something[foo] and something[foo] = x work as expected

答案 1 :(得分:64)

这是我的解决方案:

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'})

答案 2 :(得分:32)

在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

答案 3 :(得分:20)

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

var suffix = " name";

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

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

这称为computed property names

答案 4 :(得分:15)

你可以通过几种不同的方式实现这一目标。

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

foo.bar;
foo['bar'];

括号表示法特别强大,因为它允许您根据变量访问属性:

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

let prop = 'bar';

foo[prop];

这可以扩展到循环对象的每个属性。由于更新的JavaScript结构,例如......的......,这似乎是多余的,但有助于说明一个用例:

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'

答案 5 :(得分:8)

已更新

我已将以下评论纳入考虑并达成一致意见。 Eval应该避免。

使用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

答案 6 :(得分:8)

您可以使用Lodash get

这样操作
_.get(object, 'a[0].b.c');

答案 7 :(得分:5)

每当需要动态访问属性时,都必须使用方括号来访问属性而不是“”。算子
语法:object [propery}

const something = { bar: "Foobar!" };
const foo = 'bar';
// something.foo; -- not correct way at it is expecting foo as proprty in  something={ foo: "value"};
// correct way is  something[foo]
alert( something[foo])

答案 8 :(得分:4)

我碰到了一种情况,我想 我想将对象属性的“地址”作为数据传递给另一个函数,然后填充对象(使用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)); 

答案 9 :(得分:2)

当你必须将参数传递给这个函数时,它会变得很有趣。

代码 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

答案 10 :(得分:1)

对于希望设置嵌套变量值的任何人,以下是操作方法:

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

答案 11 :(得分:0)

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

干杯!

答案 12 :(得分:0)

通过引用查找对象,不包含字符串, 请注意,请确保您传递的对象是克隆对象,我为此使用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
}

答案 13 :(得分:0)

在js中访问动态对象属性,我们可以使用括号符号。

import UIKit
import StoreKit
        
class settingsViewController: UIViewController, SKPaymentTransactionObserver {
            
        let productID1 = "example.productID1"
        let productID2 = "example.productID2"
        
        
        override func viewDidLoad() {
            super.viewDidLoad()
        }
        
        //MARK: Purchase buttons
        
        @IBAction func didTapBuy1(_ sender: Any) {
            SKPaymentQueue.default().add(self)
            if SKPaymentQueue.canMakePayments() {
                let paymentRequest = SKMutablePayment()
                paymentRequest.productIdentifier = productID1
                SKPaymentQueue.default().add(paymentRequest)
            } else {
              }
        }
        
        @IBAction func didTapBuy2(_ sender: Any) {
            SKPaymentQueue.default().add(self)
            if SKPaymentQueue.canMakePayments() {
                let paymentRequest = SKMutablePayment()
                paymentRequest.productIdentifier = productID2
                SKPaymentQueue.default().add(paymentRequest)
            } else {
            }
        }
        
        
        func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) {
            for transaction in transactions {
                if transaction.transactionState == .purchased {
                        let t: SKPaymentTransaction = transaction
                        let prodID = t.payment.productIdentifier as String
                        if prodID == "example.productID1" {
                            UserDefaults.standard.setValue(true, forKey: "product1purchased")
                        }
                        if prodID == "example.productID2" {
                            UserDefaults.standard.setValue(true, forKey: "product2purchased")
                        }
                    SKPaymentQueue.default().finishTransaction(transaction)
                    
                    //MARK: .restored
                } else if transaction.transactionState == .restored {
                        let t: SKPaymentTransaction = transaction
                        let prodID = t.payment.productIdentifier as String
                        if prodID == "example.productID1" {
                            UserDefaults.standard.setValue(true, forKey: "product1purchased")
                        }
                        if prodID == "example.productID2" {
                            UserDefaults.standard.setValue(true, forKey: "product2purchased")
                        }
                    SKPaymentQueue.default().finishTransaction(transaction)
                    
                } else if transaction.transactionState == .failed {
                    SKPaymentQueue.default().finishTransaction(transaction)
                
                } else if transaction.transactionState == .purchasing {
                    
                } else if transaction.transactionState == .deferred {

                }
            }
        }
        
        //MARK: Restore Button
        @IBAction func restoreButton(_ sender: Any) {
            SKPaymentQueue.default().add(self)
            SKPaymentQueue.default().restoreCompletedTransactions()
        }
        
        func paymentQueueRestoreCompletedTransactionsFinished(_ queue: SKPaymentQueue) {
            //UI updater func() is here
        }
    }

答案 14 :(得分:0)

要动态访问属性,只需使用 square brackets [] 如下:

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

问题

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

以下是此问题的说明。这里我们有一个看起来很无辜的程序,但它有一个微妙的错误 - 你能发现它吗?

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`)
}

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

解决方案

  1. 改用 Map data structure。地图的存储内容不会受到原型问题的影响,因此它们为这个问题提供了一个干净的解决方案。

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

  

  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

  

  1. 如果您处理的对象的不同可能键是预先知道的(或者,至少知道不包含与继承键冲突的键,例如数字键),那么您可以使用 Object.hasOwn(yourObj, attrName) 代替, 检查您正在访问的特定动态密钥是否实际上是继承的密钥(了解更多信息 here)。在撰写本文时,这是浏览器刚刚开始实施的 JavaScript 的第 3 阶段提案,这意味着为了获得最佳稳定性,您需要使用 polyfill 或使用较旧的、更冗长的,否则正是相同的解决方案 Object.prototype.hasOwnProperty.call(yourObj, attrName)(我将在下面的示例中使用)。 yourObj.hasOwnProperty(attrName) 是另一种有时有效的解决方案 - 我不会在这里介绍它的陷阱,相反,您可以了解它here

// 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.prototype.hasOwnProperty.call(user, propName)) {
  console.log(`${propName} = ${user[propName]}`)
} else {
  console.log(`${propName} is not found`)
}

答案 15 :(得分:-1)

有几种可能性:

const test = {
    prop1: {
      prop2: {
        prop3: "I'm very nested"
      }
    }

const test1 = test.prop1.prop2.prop3
const test2 = test['prop1']['prop2']['prop3']
const test3 = test['prop1.prop2.prop3'] //will return undefined
const test4 = _.get(test, 'prop1.prop2.prop3') //use lodash

如果您想动态获取嵌套值(例如通过变量),则最好的选择是使用lodash

答案 16 :(得分:-2)

您应该使用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)

答案 17 :(得分:-3)

const something = { bar: "Foobar!" };
const foo = 'bar';

something[\`${foo}\`];