Các phép gán biến JavaScript từ các bộ giá trị


98

Trong các ngôn ngữ khác như Python 2 và Python 3, bạn có thể xác định và gán giá trị cho một biến tuple và truy xuất các giá trị của chúng như sau:

tuple = ("Bob", 24)
name, age = tuple
print(name)           #name evaluates to Bob
print(age)            #age evaluates to 24

Có điều gì tương tự trong JavaScript không? Hay tôi chỉ cần làm theo cách xấu xí với một mảng:

tuple = ["Bob", 24]
name = tuple[0]       //name Evaluates to Bob
age = tuple[1]        //age Evaluates to 24

Có cách nào tốt hơn để mô phỏng bộ dữ liệu Python trong JavaScript 5 không?

Cập nhật: Xem câu trả lời về ES6, nên được ưu tiên hơn CoffeeScript cho các dự án mới.


12
Trong JavaScript, đừng quên khai báo các biến:var tuple, name, age;
Šime Vidas

3
var name=tuple[0], age=tuple[1]; Đó là cách gõ nhiều hơn một chút, nhưng xấu xí có thể là một lời nói quá.
Brent Bradburn

Câu trả lời:


119

Javascript 1.7 đã thêm phép gán bị hủy cho phép bạn thực hiện về cơ bản những gì bạn đang làm.

function getTuple(){
   return ["Bob", 24];
}
var [a, b] = getTuple();
// a === "bob" , b === 24 are both true

5
Đây không phải là javascript dựa trên tiêu chuẩn, mà là các phần mở rộng dành riêng cho Mozilla.
ninjagecko

14
@ninjagecko: "JavaScript" là cách triển khai của Mozilla và các nhiệm vụ tái cấu trúc sẽ là một phần của tiêu chuẩn ecmascript sắp tới
Bergi

64
Trên thực tế, nó là một phần của ES6.
Pier Paolo Ramon

9
Trong một vài năm, câu trả lời của tôi đã trở nên đúng về mặt kỹ thuật nhưng không hữu ích cho cả chính xác và hữu ích. Yay!
pc1oad1etter

49

Bạn phải làm điều đó theo cách xấu xí. Nếu bạn thực sự muốn một cái gì đó như thế này, bạn có thể xem CoffeeScript , có cái đó và rất nhiều tính năng khác khiến nó trông giống python hơn (xin lỗi vì làm cho nó giống như một quảng cáo, nhưng tôi thực sự thích nó.)


Hmm, điều này khá thú vị, tôi vừa chạy trên kịch bản này, vì JavaScript dường như không cung cấp hỗ trợ tuple rõ ràng và đến từ giai đoạn lập trình chức năng căng thẳng, bạn phát triển mong muốn cho các bộ giá trị. Tôi cũng vừa tìm thấy điều này, nhưng không chắc liệu nó có hoạt động hay không, nó cũng trông tốt về mặt hỗ trợ tuple: cs.umd.edu/projects/PL/arrowlets/api-tuples.xhtml . Tôi chắc chắn sẽ xem xét CoffeeScript.
9codeMan9

29

Bạn có thể làm điều gì đó tương tự:

var tuple = Object.freeze({ name:'Bob', age:14 })

và sau đó tham chiếu đến tên và tuổi làm thuộc tính

tuple.name 
tuple.age 

5
Tôi sẽ không phản đối nhưng về mặt kỹ thuật thì điều này không chính xác. Bạn vẫn có thể thay đổi (tức là thay đổi) các giá trị của tuple.name và tuple.age sau khi đối tượng được khai báo. Theo định nghĩa, các kiểu bất biến không thể thay đổi sau khi chúng được xác định. Chúng giống như các loại chỉ đọc trong đó cả tham số và giá trị của chúng chỉ có thể được khai báo một lần.
Evan Plaice

4
@EvanPlaice nếu khả năng thay đổi là một vấn đề, bạn có thể sử dụng Object.freeze(), tức là:tuple = Object.freeze({ name:'Bob', age:14 })
canon

@canon Tôi đồng ý, đó có lẽ là cách tiếp cận đúng / chấp nhận được duy nhất trong toàn bộ chủ đề này. Thật không may, câu trả lời của mcm không đóng băng đối tượng nên nó vẫn có thể biến đổi.
Evan Plaice

@EvanPlaice Tôi không thấy vấn đề về khả năng đột biến đến từ đâu - các bộ giá trị không thể thay đổi trong ví dụ Python ban đầu!
Daniel Buckmaster

@DanielBuckmaster Sự khác biệt giữa một danh sách và một tuple trong Python là, một danh sách có thể thay đổi được trong khi một tuple thì không. Xem docs.python.org/2/tutorial/… . Tuples không được hỗ trợ nguyên bản trong JavaScript vì tất cả các cấu trúc dữ liệu JS đều có thể thay đổi trừ khi bạn gọi Object.freeze () trên đối tượng sau khi tạo.
Evan Plaice

27

Tính năng "tuple" này được gọi là hủy cấu trúc trong EcmaScript2015 và sẽ sớm được hỗ trợ bởi các trình duyệt cập nhật. Hiện tại, chỉ có Firefox và Chrome hỗ trợ nó .

Nhưng này, bạn có thể sử dụng một trình chuyển đổi .

Mã sẽ trông đẹp như python:

let tuple = ["Bob", 24]
let [name, age] = tuple

console.log(name)
console.log(age)

2
Đối với độc giả trong tương lai: tính năng này được hỗ trợ trong chrome kể từ chrome 49 (theo tài liệu của Mozilla). Bạn cũng có thể kiểm tra tính tương thích bằng tài liệu Mozilla tại đây: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
Jamie

12

Một mảng cố định hoạt động giống hệt như một bộ mã python:

const tuple = Object.freeze(["Bob", 24]);
let [name, age]; = tuple
console.debug(name); // "Bob"
console.debug(age); // 24

Hãy ưa thích và xác định một lớp học

class Tuple extends Array { 
  constructor(...items) { 
    super(...items); 
    Object.freeze(this);
  } 
}

let tuple = new Tuple("Jim", 35);
let [name, age] = tuple;
console.debug(name); // Jim
console.debug(age); // 35
tuple = ["Bob", 24]; // no effect 
console.debug(name); // Jim
console.debug(age); // 25

Hoạt động ngày nay trên tất cả các trình duyệt mới nhất.


Bạn không thể đặt nó thành const? Const là bất biến, không?
Đánh dấu A

2
Không. Hằng số không thể chuyển nhượng lại. Bạn không thể thực hiện const tuple = ["Jim", 35]; tuple = ["James", 35]. Bạn có thể thực hiện const tuple = ["Jim", 35]; tuple [0] = "James"; Do đó nó không phải là bất biến.
Matthew James Davis

6

Tuples không được hỗ trợ trong JavaScript

Nếu bạn đang tìm kiếm một danh sách bất biến, Object.freeze () có thể được sử dụng để làm cho một mảng trở nên bất biến.

Phương thức Object.freeze () đóng băng một đối tượng: nghĩa là, ngăn các thuộc tính mới được thêm vào nó; ngăn các thuộc tính hiện có bị xóa; và ngăn các thuộc tính hiện có hoặc khả năng liệt kê, khả năng cấu hình hoặc khả năng ghi của chúng bị thay đổi. Về bản chất, đối tượng được tạo ra một cách hiệu quả là bất biến. Phương thức trả về đối tượng đang bị đóng băng.

Nguồn: Mạng nhà phát triển Mozilla - Object.freeze ()

Gán một mảng như bình thường nhưng khóa nó bằng cách sử dụng 'Object.freeze ()

> tuple = Object.freeze(['Bob', 24]);
[ 'Bob', 24 ]

Sử dụng các giá trị như bạn làm với một mảng thông thường (không hỗ trợ nhiều phép gán trong python)

> name = tuple[0]
'Bob'
> age = tuple[1]
24

Cố gắng chỉ định một giá trị mới

> tuple[0] = 'Steve'
'Steve'

Nhưng giá trị không thay đổi

> console.log(tuple)
[ 'Bob', 24 ]

Bên cạnh đó, hy vọng Tuples sẽ được hỗ trợ hạng nhất trong ES6. Tuple gốc thực sự (tức là chuỗi không đồng nhất) cũng sẽ cải thiện tốc độ.
Evan Plaice

5

Rất tiếc, bạn không thể sử dụng cú pháp gán tuple đó trong Tập lệnh (ECMA | Java).

CHỈNH SỬA: Ai đó đã liên kết với Mozilla / JS 1.7 - điều này sẽ không hoạt động trên nhiều trình duyệt nhưng nếu điều đó không bắt buộc thì sẽ có câu trả lời của bạn.


3

Điều này không nhằm mục đích thực sự được sử dụng trong cuộc sống thực, chỉ là một bài tập thú vị. Xem Tại sao sử dụng hàm eval trong JavaScript là một ý tưởng tồi? để biết chi tiết.

Đây là tiện ích gần nhất mà bạn có thể nhận được mà không cần dùng đến các tiện ích mở rộng dành riêng cho nhà cung cấp:

myArray = [1,2,3];
eval(set('a,b,c = myArray'));

Chức năng trợ giúp:

function set(code) {
    var vars=code.split('=')[0].trim().split(',');
    var array=code.split('=')[1].trim();
    return 'var '+vars.map(function(x,i){return x+'='+array+'['+i+']'}).join(',');
}

Bằng chứng rằng nó hoạt động trong phạm vi tùy ý:

(function(){
    myArray = [4,5,6];
    eval(set('x,y,z = myArray'));
    console.log(y);  // prints 5
})()

eval không được hỗ trợ trong Safari.


5
+1 vì siêu thông minh, tuy nhiên, đừng bao giờ sử dụng điều này trong cuộc sống thực :-p
Jamund Ferguson

3

Để cập nhật câu trả lời của Bộ trưởng, bây giờ bạn có thể làm điều này với es2015:

function Tuple(...args) {
  args.forEach((val, idx) => 
    Object.defineProperty(this, "item"+idx, { get: () => val })
  )
}


var t = new Tuple("a", 123)
console.log(t.item0) // "a"
t.item0 = "b"
console.log(t.item0) // "a"

https://jsbin.com/fubaluwimo/edit?js,console


Không có lý do tại sao bạn không thể làm điều này trước khi ES2015 ... Ngoài này không trả lời câu hỏi của OP, anh hỏi cho destructuring
ThatWeirdo

3

Bạn cũng có thể có một loại tuple trong Javascript. Chỉ cần xác định nó với các hàm bậc cao hơn (thuật ngữ học thuật là mã hóa Giáo hội):

const Tuple = (...args) => {
  const Tuple = f => f(...args);
  return Object.freeze(Object.assign(Tuple, args));
};

const get1 = tx => tx((x, y) => x);

const get2 = tx => tx((x, y) => y);

const bimap = f => g => tx => tx((x, y) => Tuple(f(x), g(y)));

const toArray = tx => tx((...args) => args);

// aux functions

const inc = x => x + 1;
const toUpperCase = x => x.toUpperCase();

// mock data

const pair = Tuple(1, "a");

// application

console.assert(get1(pair) === 1);
console.assert(get2(pair) === "a");

const {0:x, 1:y} = pair;
console.log(x, y); // 1 a

console.log(toArray(bimap(inc) (toUpperCase) (pair))); // [2, "A"]

const map = new Map([Tuple(1, "a"), Tuple(2, "b")]);
console.log(map.get(1), map.get(2)); // a b

Xin lưu ý rằng Tuplenó không được sử dụng như một hàm tạo bình thường. Giải pháp hoàn toàn không dựa vào hệ thống nguyên mẫu mà chỉ dựa vào các chức năng bậc cao.

Ưu điểm của bộ giá trị so với Arrays được sử dụng như bộ giá trị? Các bộ mã hóa của nhà thờ là bất biến theo thiết kế và do đó ngăn ngừa các tác dụng phụ do đột biến gây ra. Điều này giúp xây dựng các ứng dụng mạnh mẽ hơn. Ngoài ra, sẽ dễ dàng hơn để suy luận về mã phân biệt giữa Arrays là loại tập hợp (ví dụ [a]) và các bộ giá trị là dữ liệu liên quan thuộc nhiều loại khác nhau (ví dụ (a, b)).


1

Đây là một triển khai Javascript Tuple đơn giản:

var Tuple = (function () {
   function Tuple(Item1, Item2) {
      var item1 = Item1;
      var item2 = Item2;
      Object.defineProperty(this, "Item1", {
          get: function() { return item1  }
      });
      Object.defineProperty(this, "Item2", {
          get: function() { return item2  }
      });
   }
   return Tuple;
})();

var tuple = new Tuple("Bob", 25); // Instantiation of a new Tuple
var name = tuple.Item1; // Assignment. name will be "Bob"
tuple.Item1 = "Kirk"; // Will not set it. It's immutable.

Đây là bộ 2-tuple, tuy nhiên, bạn có thể sửa đổi ví dụ của tôi để hỗ trợ các bộ 3,4,5,6, v.v.


Trên thực tế đây không phải là một t-uple mà là một cặp.
Pier Paolo Ramon

Phiên bản tuplevẫn có thể thay đổi, vì vậy về mặt kỹ thuật nó không phải là một bộ tuple. Đối với thay đổi bằng chứng tuple.Item1 = "Steve"thì console.log()đầu ra.
Evan Plaice

1
Cảm ơn vì đã tìm thấy điều đó. Tôi đã sửa đổi ví dụ để làm cho Tuple bất biến.
Faris Zacina

Làm thế nào để bạn sửa đổi điều này để hỗ trợ một độ dài tùy ý?
aij

Này không trả lời câu hỏi của OP, anh hỏi cho destructuring
ThatWeirdo

0

Đây là phiên bản câu trả lời của Matthew James Davis với các phương thức tuple Python được thêm vào:

class Tuple extends Array { 
  constructor(...items) { 
    super(...items); 
    Object.freeze(this);
  }
  toArray() {
    return [...this];
  }
  toString() {
    return '('+super.toString()+')';
  }
  count(item) {
    var arr = this.toArray();
    var result = 0;
    for(var i = 0; i < arr.length; i++) {
       if(arr[i] === item) {
         result++;
       }
    }
    return result;
  }

  

  
}

   let tuple = new Tuple("Jim", 35);
   let [name,age] = tuple;

console.log("tuple:"+tuple)
console.log("name:"+name)
console.log("age:"+age)

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.