Tự động truy cập thuộc tính đối tượng bằng cách sử dụng biến


722

Tôi đang cố gắng truy cập vào một thuộc tính của một đối tượng bằng tên động. Điều này có thể không?

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

Câu trả lời:


959

hai cách để truy cập các thuộc tính của một đối tượng:

  • Ký hiệu chấm: something.bar
  • Ký hiệu khung: something['bar']

Giá trị giữa các dấu ngoặc có thể là bất kỳ biểu thức nào. Do đó, nếu tên thuộc tính được lưu trữ trong một biến, bạn phải sử dụng ký hiệu ngoặc:

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

34
cẩn thận với điều này: trình biên dịch javascript sẽ lỗi ở đây vì chúng không đổi tên chuỗi nhưng chúng đổi tên thuộc tính đối tượng
chacham15

6
Một số thông tin thêm về lý do tại sao điều này là có thể: Các đối tượng JS là các mảng kết hợp, đó là lý do tại sao. Đọc thêm: quirksmode.org/js/associative.html stackoverflow.com/questions/14031368/
Sudhanshu Mishra

@dotnetguy Không có họ thì không. Mảng là các đối tượng kế thừa từ nguyên mẫu đối tượng JS đơn giản và do đó bạn có thể thêm các thuộc tính đi giống như bất kỳ đối tượng đơn giản nào. Hành vi 'kết hợp' giống như đối tượng hơn là mảng. Bạn không thể lặp lại phiên bản 'liên kết' bằng chỉ mục đơn giản để nó không hiển thị hành vi giống như mảng. Bạn có thể định nghĩa mảng 'liên kết' của mình là {} hoặc [] và xử lý nó giống nhau trong cả hai trường hợp liên quan đến truy cập thuộc tính ngẫu nhiên.
Vanquished Wombat

3
@VanquishedWombat Không chắc chắn sự phản đối của bạn liên quan đến điều gì? Tôi không nói rằng các đối tượng JS là mảng?
Sudhanshu Mishra

1
Câu trả lời này được bình chọn quá mức, nó không làm rõ gì cả ...
Aft3rL1f3

104

Đây là giải pháp của tôi:

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

Ví dụ sử dụng:

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

Câu trả lời tuyệt vời, xem thêm: stackoverflow.com/questions/37510640/ từ
Julian Knight

2
Bạn đã truyền cảm hứng cho tôi để tạo một phiên bản nâng cao cho phép ký hiệu và tên thuộc tính có dấu cách cũng như xác thực các đầu vào: it.knightnet.org.uk/kb/node-js/get-propericat
Julian Knight

Tôi thích giải pháp này. Tuy nhiên, tôi đang cố gắng sửa đổi các giá trị trong đối tượng ban đầu, có vẻ như hàm của bạn trả về một bản sao phụ của đối tượng. Có thể thay đổi nó để sửa đổi đối tượng trả về sửa đổi bản gốc?
Eagle1

40

Trong javascript chúng ta có thể truy cập bằng:

  • ký hiệu chấm - foo.bar
  • dấu ngoặc vuông - foo[someVar]hoặcfoo["string"]

Nhưng chỉ trường hợp thứ hai cho phép truy cập các thuộc tính một cách linh hoạt:

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
Tôi đang nhìn chằm chằm vào 2.000 dòng lệnh if vì nhà phát triển trước không sử dụng dấu ngoặc vuông và các thuộc tính đối tượng được truy cập tĩnh bằng ký hiệu dấu chấm. Đó là một ứng dụng quy trình phê duyệt có 7 người phê duyệt khác nhau và các bước đều giống nhau. / rip
Chad

26

Sau đây là một ví dụ ES6 về cách bạn có thể truy cập vào thuộc tính của một đối tượng bằng cách sử dụng tên thuộc tính đã được tạo động bằng cách nối hai chuỗi.

var suffix = " name";

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

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

Đây được gọi là tên tài sản tính toán


16

Bạn có thể đạt được điều này theo nhiều cách khác nhau.

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

foo.bar;
foo['bar'];

Ký hiệu khung là đặc biệt mạnh mẽ vì nó cho phép bạn truy cập một thuộc tính dựa trên một biến:

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

let prop = 'bar';

foo[prop];

Điều này có thể được mở rộng để lặp qua mọi thuộc tính của một đối tượng. Điều này có thể có vẻ dư thừa do các cấu trúc JavaScript mới hơn như ... của ..., nhưng giúp minh họa trường hợp sử dụng:

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

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

Cả ký hiệu dấu chấm và dấu ngoặc cũng hoạt động như mong đợi đối với các đối tượng lồng nhau:

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

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

Phá hủy đối tượng

Chúng ta cũng có thể coi việc phá hủy đối tượng như một phương tiện để truy cập vào một tài sản trong một đối tượng, nhưng như sau:

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'

11

Bạn có thể làm như thế này bằng cách sử dụng Lodash get

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

Có nhiều tình huống, chẳng hạn như tra cứu đối tượng lồng nhau sâu, trong đó đây là lựa chọn duy nhất.
Jonathan Kempf

8

CẬP NHẬT

Tôi đã xem xét ý kiến ​​dưới đây và đồng ý. Eval là để tránh.

Truy cập các thuộc tính gốc trong đối tượng có thể dễ dàng đạt được obj[variable], nhưng việc lồng ghép làm phức tạp mọi thứ. Không viết mã đã viết tôi đề nghị sử dụng lodash.get.

Thí dụ

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

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

Lodash get có thể được sử dụng theo nhiều cách khác nhau, đây là liên kết đến tài liệu lodash.get


4
Tốt nhất là tránh sử dụng evalbất cứ khi nào có thể. stackoverflow.com/questions/86513/ cường
Luke

8
Sử dụng evalcho một cái gì đó tầm thường như truy cập các thuộc tính là quá mức cần thiết và hầu như không được khuyến khích trong bất kỳ trường hợp nào. "Rắc rối" là gì? obj['nested']['test']hoạt động rất tốt và không yêu cầu bạn phải nhúng mã trong chuỗi.
Kyll

3
eval chậm hơn ba lần hoặc nhiều hơn, tôi sẽ không đề xuất điều này cho người mới vì nó có thể dạy cho họ những thói quen xấu. Tôi sử dụng obj['nested']['value']- nhớ những đứa trẻ, eval là xấu xa!
jaggedsoft

1
@Luke Bây giờ anh ấy chỉ muốn mang Lodash _.getđến bàn. Tôi nghĩ rằng câu trả lời này xứng đáng bây giờ upvote thay vì downvote. Nó có thể là quá mức cần thiết, nhưng thật tốt khi biết nó tồn tại.
Emile Bergeron

1
Cảm ơn bạn đã giới thiệu lodash cho điều này. Tôi đến đây bằng cách google tìm kiếm một phương thức để đặt giá trị sâu trong một đối tượng và sử dụng phương thức _.set của họ (giống hệt ở trên nhưng với phần tranh luận thêm về giá trị cần đặt).
TPHughes

5

Bất cứ khi nào bạn cần truy cập vào tài sản một cách linh hoạt, bạn phải sử dụng dấu ngoặc vuông để truy cập thuộc tính không "." Toán tử
Cú pháp: object [orthy}

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])


4

Tôi đã gặp một trường hợp mà tôi nghĩ rằng tôi muốn chuyển "địa chỉ" của một thuộc tính đối tượng dưới dạng dữ liệu sang một hàm khác và điền vào đối tượng (với AJAX), tìm kiếm từ mảng địa chỉ và hiển thị trong hàm khác đó. Tôi không thể sử dụng ký hiệu dấu chấm mà không thực hiện các thao tác nhào lộn chuỗi vì vậy tôi nghĩ rằng một mảng có thể tốt để vượt qua. Cuối cùng tôi đã làm một cái gì đó khác nhau, nhưng dường như liên quan đến bài viết này.

Đây là một mẫu của một đối tượng tệp ngôn ngữ như dữ liệu tôi muốn từ:

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

Tôi muốn có thể vượt qua một mảng như: ["audioPlayer", "controls", "stop"] để truy cập văn bản ngôn ngữ, "dừng" trong trường hợp này.

Tôi đã tạo ra hàm nhỏ này tìm kiếm tham số địa chỉ "ít cụ thể nhất" (đầu tiên) và gán lại đối tượng được trả về cho chính nó. Sau đó, nó đã sẵn sàng để tra cứu tham số địa chỉ cụ thể nhất tiếp theo nếu có.

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

sử dụng:

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

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

2

Thật thú vị khi bạn phải truyền tham số cho chức năng này.

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

1

ES5 // Kiểm tra các biến được lồng sâu

Đoạn mã đơn giản này có thể kiểm tra sự tồn tại của biến / giá trị được lồng sâu mà không cần phải kiểm tra từng biến trên đường đi ...

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

Ví dụ. - một mảng sâu của các đối tượng:

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

Thay vì :

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

Bây giờ chúng ta có thể:

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

Chúc mừng!


1
Nếu giải pháp là sử dụng eval, bạn chỉ cần tạo ra một triệu vấn đề khác.
Rodrigo Leite

@RodrigoLeite ok, vì vậy sẽ không có vấn đề gì khi cung cấp ít nhất một ...


1
@RodrigoLeite Tôi đã đọc nó và cập nhật giải pháp để sử dụng Functionthay thế

0

Tôi đã hỏi một câu hỏi trùng lặp về chủ đề này một thời gian trước, và sau khi nghiên cứu quá mức, và thấy rất nhiều thông tin bị thiếu ở đây, tôi cảm thấy mình có một cái gì đó có giá trị để thêm vào bài viết cũ này.

  • Đầu tiên tôi muốn giải quyết rằng có một số cách để có được giá trị của một tài sản và lưu trữ nó trong Biến động. Cách phổ biến nhất và dễ nhất IMHO sẽ là:
let properyValue = element.style['enter-a-property'];

tuy nhiên tôi hiếm khi đi theo tuyến đường này vì nó không hoạt động trên các giá trị thuộc tính được gán qua biểu định kiểu. Để cho bạn một ví dụ, tôi sẽ chứng minh bằng một chút mã giả.

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

Sử dụng ví dụ mã ở trên; nếu thuộc tính chiều rộng của phần tử div được lưu trữ trong biến 'elem' được tạo kiểu trong biểu định kiểu CSS và không được tạo kiểu bên trong thẻ HTML của nó, bạn chắc chắn sẽ nhận được giá trị trả về của giá trị không xác định được lưu trữ bên trong của biến cssProp. Giá trị không xác định xảy ra bởi vì để có được giá trị chính xác, do đó, mã được viết bên trong CSS Style-Sheet cần được tính toán theo thứ tự để có được giá trị, do đó; bạn phải sử dụng một phương pháp sẽ tính toán giá trị của tài sản mà giá trị của chúng nằm trong biểu định kiểu.

  • Do đó, phương thức getComputingStyle ()!
function getCssProp(){
  let ele = document.getElementById("test");
  let cssProp = window.getComputedStyle(ele,null).getPropertyValue("width");
}

W3Schools getComputingValue Doc Đây là một ví dụ hay và cho phép bạn chơi với nó, tuy nhiên, liên kết này Mozilla CSS getComputingValue doc nói về hàm getComputingValue một cách chi tiết và nên được đọc bởi bất kỳ nhà phát triển khao khát nào không hiểu rõ về chủ đề này.

  • Là một lưu ý phụ, phương thức getComputingValue chỉ nhận được, nó không được đặt. Đây rõ ràng là một nhược điểm lớn, tuy nhiên có một phương pháp lấy từ các biểu định kiểu CSS, cũng như đặt các giá trị, mặc dù đó không phải là Javascript tiêu chuẩn. Phương thức JQuery ...
$(selector).css(property,value)

... không nhận, và không thiết lập. Đó là những gì tôi sử dụng, nhược điểm duy nhất là bạn đã biết JQuery, nhưng đây thực sự là một trong rất nhiều lý do tốt mà mọi Nhà phát triển Javascript nên học JQuery, nó giúp cuộc sống trở nên dễ dàng và cung cấp các phương thức, như cách này, không có sẵn với Javascript tiêu chuẩn. Hy vọng điều này sẽ giúp được ai đó !!!


0

Đối với bất kỳ ai đang tìm cách đặt giá trị của biến lồng nhau, đây là cách thực hiện:

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

Tài liệu: https://lodash.com/docs/4.17.15#set

Ngoài ra, tài liệu nếu bạn muốn nhận giá trị: https://lodash.com/docs/4.17.15#get



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

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

7
Tại sao trên trái đất bạn sẽ làm điều đó? Của bạn foođã là một chuỗi, do đó, `${foo}`chính xác như là foo. (Ngoài ra, mã của bạn dường như có một số dấu xồ nguợc bổ sung mà không làm thuộc có Nhưng nó vẫn sẽ là vô nghĩa ngay cả khi bạn cố định mà lỗi cú pháp..)
Ilmari Karonen
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.