Có thể thêm các thuộc tính được đặt tên động vào đối tượng JavaScript không?


745

Trong JavaScript, tôi đã tạo một đối tượng như vậy:

var data = {
    'PropertyA': 1,
    'PropertyB': 2,
    'PropertyC': 3
};

Có thể thêm các thuộc tính khác cho đối tượng này sau khi tạo ban đầu nếu tên thuộc tính không được xác định cho đến thời gian chạy không? I E

var propName = 'Property' + someUserInput
//imagine someUserInput was 'Z', how can I now add a 'PropertyZ' property to 
//my object?

Câu trả lời:


1211

Đúng.

var data = {
    'PropertyA': 1,
    'PropertyB': 2,
    'PropertyC': 3
};

data["PropertyD"] = 4;

// dialog box with 4 in it
alert(data.PropertyD);
alert(data["PropertyD"]);


142
@thedz: data.PropertyD cần biết tên thuộc tính, không đủ năng động.
Georg Schölly

6
+1 vì điều này đã giúp tôi. Nhưng tôi không hiểu tại sao một thuộc tính đối tượng được xử lý như một mảng.
Ron van der Heijden

9
@Bondye: Đó là một phần trong thiết kế kỳ lạ của javascript. Trong trường hợp object["property"]này không hoàn toàn giống như array[4], trước đây không được tạo như một mảng thực sự.
Georg Schölly

5
Có phải chỉ tôi hoặc bài đăng này không trả lời câu hỏi trong khi nhận được 195 lượt upvote? Tôi nghĩ rằng nó đang hỏi làm thế nào để xác định các thuộc tính trong đó tên không xác định cho đến khi nó được tạo trong mã JavaScript.
Qantas 94 Nặng

20
@Qantas: Hãy nói rằng nó không trả lời trực tiếp. Nhưng đi từ data["PropertyD"]đếndata[function_to_get_property_name()] có vẻ tầm thường.
Georg Schölly

154

ES6 để giành chiến thắng!

const b = 'b';
const c = 'c';

const data = {
    a: true,
    [b]: true, // dynamic property
    [`interpolated-${c}`]: true, // dynamic property + interpolation
    [`${b}-${c}`]: true
}

Nếu bạn đăng nhập data bạn nhận được điều này:

{
  a: true,
  b: true,
  interpolated-c: true,
  b-c: true
}

Điều này làm cho việc sử dụng cú pháp Thuộc tínhMẫu văn bản mới .


1
Đây là những gì tôi cần trong trường hợp tôi muốn mã của mình hoàn toàn hoạt động (như trong, không có tuyên bố bắt buộc nào nói obj[propname]). Thay vào đó, tôi đã có thể sử dụng điều này với cú pháp trải rộng đối tượng.
intcreator

2
Không rõ ràng ngay lập tức đoạn mã này đang làm gì với người chưa xem hoặc hiểu cú pháp mới. Tôi sẽ đề xuất một chỉnh sửa để hiển thị đầu ra / phù hợp dự kiến ​​với 'a' const.

Cá nhân, tôi nghĩ rằng cách ES5 gọn gàng và dễ hiểu hơn nhiều:var a = {}; a["dynamic-" + prop] = true;
Jack Giffin

1
@JackGiffin trong một số trường hợp có, nhưng khi làm việc với các cấu trúc bất biến, cú pháp này có thể rất tiện dụng, vì cách tiếp cận bạn đưa ra là đột biến a. (Đặc biệt khi sử dụng các gói như redux)
Mauricio Soares

3
Đây chỉ là {... bang, [prop]: val}
Xipo

87

Vâng, nó là có thể. Giả định:

var data = {
    'PropertyA': 1,
    'PropertyB': 2,
    'PropertyC': 3
};
var propertyName = "someProperty";
var propertyValue = "someValue";

Hoặc:

data[propertyName] = propertyValue;

hoặc là

eval("data." + propertyName + " = '" + propertyValue + "'");

Phương pháp đầu tiên được ưa thích. eval () có mối quan tâm bảo mật rõ ràng nếu bạn đang sử dụng các giá trị do người dùng cung cấp, vì vậy đừng sử dụng nó nếu bạn có thể tránh nó nhưng đáng để biết nó tồn tại và những gì nó có thể làm.

Bạn có thể tham khảo điều này với:

alert(data.someProperty);

hoặc là

data(data["someProperty"]);

hoặc là

alert(data[propertyName]);

40
Sử dụng eval thực sự nguy hiểm.
Georg Schölly

10
Chưa kể chậm.
Eamon Nerbonne

@ GeorgSchölly Đúng.
Obinna Nwakwue

1
Lưu ý (trong trường hợp ai đó gặp phải vấn đề tương tự như tôi đã làm): Đối với các đối tượng bình thường, điều này hoạt động tốt. Nhưng tôi đã phải thêm một số thuộc tính vào một đối tượng UI jQuery để theo dõi danh sách các mục. Trong trường hợp đó, thuộc tính đã bị mất nếu được thêm theo cách này vì jQuery luôn tạo một bản sao. Ở đây bạn cần sử dụng jQuery.extend () .
Matt

Tôi muốn thêm vào nhận xét trước đây của mình - ngay cả điều đó không hoạt động trong trường hợp của tôi. Vì vậy, tôi đã kết thúc bằng cách sử dụng $("#mySelector").data("propertyname", myvalue);để thiết lập và var myValue=$("#mySelector").data("propertyname");để lấy lại giá trị. Ngay cả các đối tượng phức tạp (danh sách, mảng ...) có thể được thêm theo cách này.
Matt

61

Tôi biết rằng câu hỏi đã được trả lời hoàn hảo, nhưng tôi cũng tìm thấy một cách khác để thêm thuộc tính mới và muốn chia sẻ nó với bạn:

Bạn có thể sử dụng chức năng Object.defineProperty()

Tìm thấy trên Mozilla Developer Network

Thí dụ:

var o = {}; // Creates a new object

// Example of an object property added with defineProperty with a data property descriptor
Object.defineProperty(o, "a", {value : 37,
                               writable : true,
                               enumerable : true,
                               configurable : true});
// 'a' property exists in the o object and its value is 37

// Example of an object property added with defineProperty with an accessor property descriptor
var bValue;
Object.defineProperty(o, "b", {get : function(){ return bValue; },
                               set : function(newValue){ bValue = newValue; },
                               enumerable : true,
                               configurable : true});
o.b = 38;
// 'b' property exists in the o object and its value is 38
// The value of o.b is now always identical to bValue, unless o.b is redefined

// You cannot try to mix both :
Object.defineProperty(o, "conflict", { value: 0x9f91102, 
                                       get: function() { return 0xdeadbeef; } });
// throws a TypeError: value appears only in data descriptors, get appears only in accessor descriptors

4
Ưu và nhược điểm của phương pháp này?
Trevor

6
@Trevor: Tổng cấu hình và khả năng thêm getters và setters; Ngoài ra, khả năng thêm nhiều thuộc tính cùng một lúc với defineProperties(số nhiều).
rvighne

@Thielicy Object.definePropertykhông có nghĩa là công cụ tiện lợi dễ dàng, nhưng là công cụ kiểm soát chi tiết. Nếu bạn không cần điều khiển bổ sung đó, thì đó không phải là công cụ phù hợp để chọn.
kleinfreund

Object.defineProperty(obj, prop, valueDescriptor)V8 chậm hơn và khó hơn rất nhiều để tối ưu hóa hơn là làm đơn giản obj[prop] = value;
Jack Giffin

27

ES6 giới thiệu tên thuộc tính được tính toán, cho phép bạn thực hiện

let a = 'key'
let myObj = {[a]: 10};
// output will be {key:10}

23

Ở đây, sử dụng ký hiệu của bạn:

var data = {
    'PropertyA': 1,
    'PropertyB': 2,
    'PropertyC': 3
};
var propName = 'Property' + someUserInput
//imagine someUserInput was 'Z', how can I now add a 'PropertyZ' property to 
//my object?
data[propName] = 'Some New Property value'

18

Bạn có thể thêm bao nhiêu thuộc tính tùy thích bằng cách sử dụng ký hiệu dấu chấm:

var data = {
    var1:'somevalue'
}
data.newAttribute = 'newvalue'

hoặc :

data[newattribute] = somevalue

cho các phím động.


4
nếu tên thuộc tính không được xác định cho đến thời gian chạy "- vì vậy sẽ không hoạt động trừ khi bạn sử dụng eval, đó không phải là một lựa chọn tốt
Marc Gravell

1
hoặc sử dụng cú pháp [] ... data [somevar] = somevalue
Gabriel Hurley

17

ngoài tất cả các câu trả lời trước đó và trong trường hợp bạn đang tự hỏi làm thế nào chúng ta sẽ viết tên thuộc tính động trong Tương lai bằng Tên thuộc tính được tính toán (ECMAScript 6), đây là cách:

var person = "John Doe";
var personId = "person_" + new Date().getTime();
var personIndex = {
    [ personId ]: person
//  ^ computed property name
};

personIndex[ personId ]; // "John Doe"

tham khảo: Hiểu ECMAScript 6 - Nickolas Zakas


11

Chỉ là một bổ sung để bỏ qua câu trả lời ở trên. Bạn có thể định nghĩa một hàm để đóng gói độ phức tạp của notifyProperty như được đề cập dưới đây.

var defineProp = function ( obj, key, value ){
  var config = {
    value: value,
    writable: true,
    enumerable: true,
    configurable: true
  };
  Object.defineProperty( obj, key, config );
};

//Call the method to add properties to any object
defineProp( data, "PropertyA",  1 );
defineProp( data, "PropertyB",  2 );
defineProp( data, "PropertyC",  3 );

tham khảo: http://addyosmani.com/resource/essentialjsdesignpotypes/book/#constructorpotypejavascript


9

Bạn có thể thêm các thuộc tính động bằng cách sử dụng một số tùy chọn bên dưới:

Trong ví dụ của bạn:

var data = {
    'PropertyA': 1,
    'PropertyB': 2,
    'PropertyC': 3
};

Bạn có thể xác định một thuộc tính có giá trị động theo hai cách tiếp theo:

data.key = value;

hoặc là

data['key'] = value;

Hơn nữa..nếu khóa của bạn cũng động, bạn có thể xác định bằng cách sử dụng lớp Object với:

Object.defineProperty(data, key, withValue(value));

trong đó dữ liệu là đối tượng của bạn, khóa là biến để lưu trữ tên khóa và giá trị là biến để lưu trữ giá trị.

Tôi hi vọng cái này giúp được!


8

Tôi biết đã có một số câu trả lời cho bài đăng này, nhưng tôi chưa thấy câu trả lời nào trong đó có nhiều thuộc tính và chúng nằm trong một mảng. Và giải pháp này là dành cho ES6.

Để minh họa, giả sử chúng ta có một mảng có tên người với các đối tượng bên trong:

 let Person = [{id:1, Name: "John"}, {id:2, Name: "Susan"}, {id:3, Name: "Jet"}]

Vì vậy, bạn có thể thêm một tài sản với giá trị tương ứng. Giả sử chúng ta muốn thêm một Ngôn ngữ có giá trị mặc định là EN .

Person.map((obj)=>({...obj,['Language']:"EN"}))

Các Person mảng bây giờ sẽ trở thành như thế này:

Person = [{id:1, Name: "John", Language:"EN"}, 
{id:2, Name: "Susan", Language:"EN"}, {id:3, Name: "Jet", Language:"EN"}]

Bạn không thực sự thêm các thuộc tính vào một đối tượng, bạn đang tạo một đối tượng mới với các thuộc tính của đối tượng cũ (thông qua toán tử trải rộng) và các đạo cụ mới.
Ed Orsi

3
Bạn đúng về điều đó nên có Person = Person.map(code here). Nhưng vấn đề là bạn có thể dễ dàng thêm thuộc tính vào một đối tượng hiện có ES6.
Edper

5

Cách đơn giản và di động nhất là.

var varFieldName = "good";
var ob = {};
Object.defineProperty(ob, varFieldName , { value: "Fresh Value" });

Dựa trên câu trả lời #abeing!


3

Hãy cẩn thận trong khi thêm một thuộc tính vào đối tượng hiện có bằng cách sử dụng . (Chấm) phương thức. .

(.dot) phương pháp thêm thuộc tính vào đối tượng chỉ nên được sử dụng nếu bạn biết trước 'khóa' nếu không sử dụng phương thức [ngoặc] .

Thí dụ:

   var data = {
        'Property1': 1
    };
    
    // Two methods of adding a new property [ key (Property4), value (4) ] to the
    // existing object (data)
    data['Property2'] = 2; // bracket method
    data.Property3 = 3;    // dot method
    console.log(data);     // { Property1: 1, Property2: 2, Property3: 3 }
    
    // But if 'key' of a property is unknown and will be found / calculated
    // dynamically then use only [bracket] method not a dot method    
    var key;
    for(var i = 4; i < 6; ++i) {
    	key = 'Property' + i;     // Key - dynamically calculated
    	data[key] = i; // CORRECT !!!!
    }
    console.log(data); 
    // { Property1: 1, Property2: 2, Property3: 3, Property4: 4, Property5: 5 }
    
    for(var i = 6; i < 2000; ++i) {
    	key = 'Property' + i; // Key - dynamically calculated
    	data.key = i;         // WRONG !!!!!
    }
    console.log(data); 
    // { Property1: 1, Property2: 2, Property3: 3, 
    //   Property4: 4, Property5: 5, key: 1999 }

Lưu ý vấn đề ở cuối nhật ký giao diện điều khiển - 'key: 1999' thay vì Property6: 6, Property7: 7, ........., Property1999: 1999 . Vì vậy, cách tốt nhất để thêm thuộc tính được tạo động là phương thức [ngoặc].


1

Một cách hay để truy cập từ các tên chuỗi động có chứa các đối tượng (ví dụ object.subobject.property)

function ReadValue(varname)
{
    var v=varname.split(".");
    var o=window;
    if(!v.length)
        return undefined;
    for(var i=0;i<v.length-1;i++)
        o=o[v[i]];
    return o[v[v.length-1]];
}

function AssignValue(varname,value)
{
    var v=varname.split(".");
    var o=window;
    if(!v.length)
        return;
    for(var i=0;i<v.length-1;i++)
        o=o[v[i]];
    o[v[v.length-1]]=value;
}

Thí dụ:

ReadValue("object.subobject.property");
WriteValue("object.subobject.property",5);

eval làm việc cho giá trị đọc, nhưng giá trị ghi khó hơn một chút.

Phiên bản nâng cao hơn (Tạo các lớp con nếu chúng không tồn tại và cho phép các đối tượng thay vì các biến toàn cục)

function ReadValue(varname,o=window)
{
    if(typeof(varname)==="undefined" || typeof(o)==="undefined" || o===null)
        return undefined;
    var v=varname.split(".");
    if(!v.length)
        return undefined;
    for(var i=0;i<v.length-1;i++)
    {
        if(o[v[i]]===null || typeof(o[v[i]])==="undefined") 
            o[v[i]]={};
        o=o[v[i]];
    }
    if(typeof(o[v[v.length-1]])==="undefined")    
        return undefined;
    else    
        return o[v[v.length-1]];
}

function AssignValue(varname,value,o=window)
{
    if(typeof(varname)==="undefined" || typeof(o)==="undefined" || o===null)
        return;
    var v=varname.split(".");
    if(!v.length)
        return;
    for(var i=0;i<v.length-1;i++)
    {
        if(o[v[i]]===null || typeof(o[v[i]])==="undefined")
            o[v[i]]={};
        o=o[v[i]];
    }
    o[v[v.length-1]]=value;
}

Thí dụ:

ReadValue("object.subobject.property",o);
WriteValue("object.subobject.property",5,o);

Điều này giống với o.object.subobject.property


1
chính xác những gì tôi đang tìm kiếm, điều này rất hữu ích để phản ứng this.setState ({động property: value}) thankyou!
Kevin Danikowski

0

Đây là cách tôi giải quyết vấn đề.

var obj = {

};
var field = "someouter.someinner.someValue";
var value = 123;

function _addField( obj, field, value )
{
    // split the field into tokens
    var tokens = field.split( '.' );

    // if there's more than one token, this field is an object
    if( tokens.length > 1 )
    {
        var subObj = tokens[0];

        // define the object
        if( obj[ subObj ] !== undefined ) obj[ subObj ] = {};

        // call addfield again on the embedded object
        var firstDot = field.indexOf( '.' );
        _addField( obj[ subObj ], field.substr( firstDot + 1 ), value );

    }
    else
    {
        // no embedded objects, just field assignment
        obj[ field ] = value;
    }
}

_addField( obj, field, value );
_addField(obj, 'simpleString', 'string');

console.log( JSON.stringify( obj, null, 2 ) );

Tạo đối tượng sau:

{
  "someouter": {
    "someinner": {
      "someValue": 123
    }
  },
  "simpleString": "string"
}

0

Nó có thể hữu ích nếu hỗn hợp thêm thuộc tính mới trong thời gian chạy:

data = { ...data, newPropery: value}

Tuy nhiên, toán tử trải rộng sử dụng bản sao nông nhưng ở đây chúng tôi gán dữ liệu cho chính nó nên không mất gì


-2

Một cách hoàn hảo dễ dàng

var data = {
    'PropertyA': 1,
    'PropertyB': 2,
    'PropertyC': 3
};

var newProperty = 'getThisFromUser';
data[newProperty] = 4;

console.log(data);

Nếu bạn muốn áp dụng nó trên một mảng dữ liệu (phiên bản ES6 / TS)

const data = [
  { 'PropertyA': 1, 'PropertyB': 2, 'PropertyC': 3 },
  { 'PropertyA': 11, 'PropertyB': 22, 'PropertyC': 33 }
];

const newProperty = 'getThisFromUser';
data.map( (d) => d[newProperty] = 4 );

console.log(data);

-14

Chắc chắn rồi. Hãy nghĩ về nó như một từ điển hoặc mảng kết hợp. Bạn có thể thêm vào nó bất cứ lúc nào.


1
Chỉ nói rằng sẽ không giúp đỡ.
Obinna Nwakwue
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.