Làm cách nào để sử dụng một biến cho một khóa trong một đối tượng JavaScript theo nghĩa đen?


406

Tại sao các công việc sau đây?

<something>.stop().animate(
    { 'top' : 10 }, 10
);

Trong khi điều này không hoạt động:

var thetop = 'top';
<something>.stop().animate(
    { thetop : 10 }, 10
);

Để làm cho nó rõ ràng hơn: Hiện tại tôi không thể chuyển một thuộc tính CSS cho hàm animate dưới dạng một biến.



Câu trả lời:


667

{ thetop : 10 }là một đối tượng hợp lệ theo nghĩa đen. Mã sẽ tạo một đối tượng có thuộc tính có tên là thetop10. Cả hai cách sau đều giống nhau:

obj = { thetop : 10 };
obj = { "thetop" : 10 };

Trong ES5 trở về trước, bạn không thể sử dụng biến làm tên thuộc tính bên trong một đối tượng bằng chữ. Tùy chọn duy nhất của bạn là làm như sau:

var thetop = "top";

// create the object literal
var aniArgs = {};

// Assign the variable property name with a value of 10
aniArgs[thetop] = 10; 

// Pass the resulting object to the animate method
<something>.stop().animate(
    aniArgs, 10  
);  

ES6 định nghĩa ComputedPropertyName như một phần của ngữ pháp cho literals đối tượng, cho phép bạn viết mã như thế này:

var thetop = "top",
    obj = { [thetop]: 10 };

console.log(obj.top); // -> 10

Bạn có thể sử dụng cú pháp mới này trong các phiên bản mới nhất của mỗi trình duyệt chính.


Tôi hiểu! Cảm ơn bạn! Shoudl không điều này cũng làm việc với eval? Tôi có nghĩa là nó không hoạt động trong ví dụ của tôi tại thời điểm này, nhưng tôi mỏng nó nên ... :-)
speendo

3
@Marcel: eval()sẽ không hoạt động bên trong một đối tượng theo nghĩa đen cho tên thuộc tính động, bạn sẽ gặp lỗi. Không chỉ vậy, nhưng eval()thực sự không nên sử dụng cho những thứ như vậy. Có một bài viết tuyệt vời về cách sử dụng đúng và không chính xác của eval: blog.msdn.com/ericlippert/archive/2003/11/01/53329.aspx
Andy E

2
@AndyE xem xét cập nhật "các phiên bản gần đây" và "TP IE hiện tại" với một số thời gian cụ thể hơn như "Phiên bản muộn hơn XXX" hoặc "sau 2014-mm" (Tôi sẽ tự thay đổi, nhưng tôi không biết giá trị nào tốt sẽ là.
Alexei Levenkov

1
đối với ES6, có cách nào để loại bỏ tài sản nếu khóa là null / không xác định? Ví dụ: trong {[key] : "value"}, nếu khóa là null, nó sẽ cung cấp { null: "value"}, trong khi tôi muốn kết quả là{}
wasabigeek

giải pháp tuyệt vời, nhưng tại sao bạn biết nhiều như vậy, thậm chí đọc toàn bộ thông số kỹ thuật không thể nhận được điểm :(
hugemeow

126

Với ECMAScript 2015, giờ đây bạn có thể thực hiện trực tiếp trong khai báo đối tượng với ký hiệu ngoặc: 

var obj = {
  [key]: value
}

Trường hợp keycó thể là bất kỳ loại biểu thức (ví dụ: một biến) trả về một giá trị.

Vì vậy, ở đây mã của bạn sẽ trông như sau:

<something>.stop().animate({
  [thetop]: 10
}, 10)

Nơi thetopsẽ được đánh giá trước khi được sử dụng làm chìa khóa.


17

Trích dẫn ES5 nói rằng nó không nên hoạt động

Lưu ý: quy tắc đã thay đổi cho ES6: https://stackoverflow.com/a/2274327/895245

Spec: http : //www.ecma-i Intl.org/ecma-262/5.1/#sec-11.1.5

Tên tài sản :

  • Tên định danh
  • Chuỗi chữ
  • Chữ số

[...]

Thuộc tính sản xuất: Tên định danh được đánh giá như sau:

  1. Trả về giá trị Chuỗi chứa cùng một chuỗi ký tự như Mã định danh.

Thuộc tính sản xuất: StringLiteral được đánh giá như sau:

  1. Trả về SV [Giá trị chuỗi] của StringLiteral.

Thuộc tính sản xuất: NumericLiteral được đánh giá như sau:

  1. Đặt nbr là kết quả của việc hình thành giá trị của NumericLiteral.
  2. Quay trở lại ToString (nbr).

Điều này có nghĩa rằng:

  • { theTop : 10 } giống hệt như { 'theTop' : 10 }

    Đây PropertyName theToplà một IdentifierName, do đó, nó được chuyển đổi thành 'theTop'giá trị chuỗi, là giá trị chuỗi của 'theTop'.

  • Không thể viết các trình khởi tạo đối tượng (bằng chữ) với các phím biến.

    Ba tùy chọn duy nhất là IdentifierName(mở rộng thành chuỗi ký tự) StringLiteralNumericLiteral(cũng mở rộng thành chuỗi).


3
Downvoters: Tôi là người đầu tiên trích dẫn bất kỳ tiêu chuẩn nào cho câu hỏi này. Trích dẫn ES6 về câu trả lời hàng đầu đã được chỉnh sửa sau khi tôi trả lời và tiêu chuẩn đó vẫn chưa được chấp nhận tại thời điểm đó. Nếu bạn tình cờ biết lý do tại sao tôi nhận được downvote, xin vui lòng giải thích, tôi chỉ muốn tìm hiểu. Tôi cũng có thể nhận được huy hiệu áp lực ngang hàng ...
Ciro Santilli 郝海东 冠状 病 六四

Tôi đoán rằng downvote chủ yếu là vì câu trả lời của bạn không đưa ra giải pháp và "không hữu ích" trong vấn đề đó. Bỏ phiếu theo áp lực ngang hàng :-)
Bergi

3
@Bergi cảm ơn vì đã can đảm! :-) Nhưng tôi nghĩ rằng tôi đã trả lời câu hỏi trực tiếp : Q: "Tại sao các công việc sau đây?". A: vì ES5 nói vậy. "Phải làm gì về nó?" là ngầm. Bạn đã hạ thấp câu hỏi hàng đầu để nói "Không thể" mà không có trích dẫn chuẩn trước khi ai đó chỉnh sửa trong giải pháp ES6?
Ciro Santilli 郝海东 冠状 病 事件

À, đúng rồi. Tôi thường trích dẫn các câu hỏi cụ thể trong một blockquote để làm cho nó rõ ràng khi tôi trả lời chúng trực tiếp. Trích dẫn tiêu chuẩn có thể làm cho một câu trả lời tốt thậm chí tốt hơn, nhưng hiện tại bài viết của bạn thậm chí không trả lời câu hỏi imo. Nói rõ những gì có thể tạo ra một khóa trong ES5 không ngụ ý cách chúng hoạt động. Chắc chắn thetoplà một IdentifierName, vậy tại sao nó không hoạt động ? Câu hỏi đó vẫn còn bỏ ngỏ.
Bergi

1
@Bergi cảm ơn lần nữa vì đã giải thích cho tôi! Tôi đã cập nhật nó để làm cho nó rõ ràng hơn. Tôi đã không làm điều đó trước đây bởi vì mặc dù điều đó là hiển nhiên, bởi vì chúng tôi có thể viết {a:1}.a, vì vậy arõ ràng không mở rộng giá trị biến trong trường hợp định danh. Nhưng có, giải thích thêm là một cải tiến trong trường hợp này.
Ciro Santilli 郝海东 冠状 病 事件

5

Tôi đã sử dụng cách sau để thêm thuộc tính có tên "động" vào đối tượng:

var key = 'top';
$('#myElement').animate(
   (function(o) { o[key]=10; return o;})({left: 20, width: 100}),
   10
);

key là tên của tài sản mới.

Đối tượng của các thuộc tính được truyền vào animatesẽ là{left: 20, width: 100, top: 10}

Đây chỉ là sử dụng []ký hiệu cần thiết theo khuyến nghị của các câu trả lời khác, nhưng với ít dòng mã hơn!


5

Thêm dấu ngoặc vuông xung quanh biến hoạt động tốt cho tôi. Thử cái này

var thetop = 'top';
<something>.stop().animate(
    { [thetop] : 10 }, 10
);

Điều này sẽ không hoạt động trong các phiên bản cũ hơn của EcmaScript, nhưng ngày nay đây là một cách tiếp cận rất rõ ràng.
Oliver

3

Tôi không thể tìm thấy một ví dụ đơn giản về sự khác biệt giữa ES6 và ES5, vì vậy tôi đã tạo một ví dụ . Cả hai mẫu mã tạo chính xác cùng một đối tượng. Nhưng ví dụ ES5 cũng hoạt động trong các trình duyệt cũ hơn (như IE11), trong đó ví dụ ES6 thì không.

ES6

var matrix = {};
var a = 'one';
var b = 'two';
var c = 'three';
var d = 'four';

matrix[a] = {[b]: {[c]: d}};

ES5

var matrix = {};
var a = 'one';
var b = 'two';
var c = 'three';
var d = 'four';

function addObj(obj, key, value) {
  obj[key] = value;
  return obj;
}

matrix[a] = addObj({}, b, addObj({}, c, d));

2

Cập nhật / ví dụ 2020 ...

Một ví dụ phức tạp hơn, sử dụng dấu ngoặc và chữ ... một cái gì đó bạn có thể phải làm ví dụ với vue / axios. Bọc nghĩa đen trong ngoặc, vì vậy

[`...`]

{
    [`filter[${query.key}]`]: query.value,  // 'filter[foo]' : 'bar'
}

1

Mã đã cho:

var thetop = 'top';
<something>.stop().animate(
    { thetop : 10 }, 10
);

Dịch:

var thetop = 'top';
var config = { thetop : 10 }; // config.thetop = 10
<something>.stop().animate(config, 10);

Như bạn có thể thấy, { thetop : 10 }khai báo không sử dụng biến thetop. Thay vào đó, nó tạo ra một đối tượng với một khóa có tên thetop. Nếu bạn muốn khóa là giá trị của biến thetop, thì bạn sẽ phải sử dụng dấu ngoặc vuông xung quanh thetop:

var thetop = 'top';
var config = { [thetop] : 10 }; // config.top = 10
<something>.stop().animate(config, 10);

Cú pháp dấu ngoặc vuông đã được giới thiệu với ES6. Trong các phiên bản trước của JavaScript, bạn sẽ phải làm như sau:

var thetop = 'top';
var config = (
  obj = {},
  obj['' + thetop] = 10,
  obj
); // config.top = 10
<something>.stop().animate(config, 10);

1

Tôi không thể tin rằng điều này chưa được đăng: chỉ sử dụng ký hiệu mũi tên với đánh giá ẩn danh!

Hoàn toàn không xâm lấn, không gây rối với không gian tên và chỉ mất một dòng:

myNewObj = ((k,v)=>{o={};o[k]=v;return o;})(myKey,myValue);

bản giới thiệu:

hữu ích trong các môi trường chưa hỗ trợ {[myKey]: myValue}cú pháp mới , chẳng hạn như Rõ ràng; Tôi vừa xác minh nó trên Bảng điều khiển dành cho nhà phát triển web của tôi Firefox Firefox 72.0.1, phát hành 2020-01-08.

(Tôi chắc chắn rằng bạn có khả năng có thể thực hiện một số giải pháp mạnh hơn / có thể mở rộng hơn hoặc bất cứ điều gì liên quan đến việc sử dụng thông minh reduce, nhưng tại thời điểm đó, bạn có thể được phục vụ tốt hơn bằng cách chỉ tạo ra chức năng Tạo đối tượng thành chức năng của chính nó thay vì gây nhiễu tất cả nội tuyến)


không phải là nó quan trọng kể từ khi OP hỏi này mười năm trước, nhưng cho đầy đủ vì lợi ích và để chứng minh nó như thế nào là chính xác các câu trả lời cho câu hỏi như đã nêu, tôi sẽ hiển thị này trong bối cảnh ban đầu:

var thetop = 'top';
<something>.stop().animate(
    ((k,v)=>{o={};o[k]=v;return o;})(thetop,10), 10
);

0

Bằng cách này bạn cũng có thể đạt được đầu ra mong muốn

var jsonobj={};
var count=0;
$(document).on('click','#btnadd', function() {
    jsonobj[count]=new Array({ "1"  : $("#txtone").val()},{ "2"  : $("#txttwo").val()});
    count++;
    console.clear();
    console.log(jsonobj);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<span>value 1</span><input id="txtone" type="text"/>
<span>value 2</span><input id="txttwo" type="text"/>
<button id="btnadd">Add</button>


0

Triển khai ES5 để gán các khóa bên dưới:

var obj = Object.create(null),
    objArgs = (
      (objArgs = {}),
      (objArgs.someKey = {
        value: 'someValue'
      }), objArgs);

Object.defineProperties(obj, objArgs);

Tôi đã đính kèm một đoạn tôi đã sử dụng để chuyển đổi thành vật thể trần.

var obj = {
  'key1': 'value1',
  'key2': 'value2',
  'key3': [
    'value3',
    'value4',
  ],
  'key4': {
    'key5': 'value5'
  }
}

var bareObj = function(obj) {

  var objArgs,
    bareObj = Object.create(null);

  Object.entries(obj).forEach(function([key, value]) {

    var objArgs = (
      (objArgs = {}),
      (objArgs[key] = {
        value: value
      }), objArgs);

    Object.defineProperties(bareObj, objArgs);

  });

  return {
    input: obj,
    output: bareObj
  };

}(obj);

if (!Object.entries) {
  Object.entries = function(obj){
    var arr = [];
    Object.keys(obj).forEach(function(key){
      arr.push([key, obj[key]]);
    });
    return arr;
  }
}

console(bareObj);


0

Bạn có thể làm như sau cho ES5:

var theTop = 'top'
<something>.stop().animate(
  JSON.parse('{"' + theTop + '":' + JSON.stringify(10) + '}'), 10
)

Hoặc trích xuất thành hàm:

function newObj (key, value) {
  return JSON.parse('{"' + key + '":' + JSON.stringify(value) + '}')
}

var theTop = 'top'
<something>.stop().animate(
  newObj(theTop, 10), 10
)


0

Bạn có thể làm theo cách này:

var thetop = 'top';
<something>.stop().animate(
    new function() {this[thetop] = 10;}, 10
);

0

Bạn cũng có thể thử như thế này:

let array1 = [{
    "description": "THURSDAY",
    "count": "1",
    "date": "2019-12-05"
},
{
    "description": "WEDNESDAY",
    "count": "0",
    "date": "2019-12-04"
}]
let res = array1.map((value, index) => {
    return { [value.description]: { count: value.count, date: value.date } }
})
console.log(res);

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.