Tuple'lardan JavaScript değişken atamaları


103

Python 2 ve Python 3 gibi diğer dillerde, bir tuple değişkenine değerler tanımlayıp atayabilir ve değerlerini şu şekilde alabilirsiniz:

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

JavaScript'te benzer bir şey var mı? Yoksa bunu bir dizi ile çirkin bir şekilde yapmak zorunda mıyım:

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

JavaScript 5'te Python tuples'i simüle etmenin daha iyi bir yolu var mı?

Güncelleme: Yeni projeler için CoffeeScript'e tercih edilmesi gereken ES6 ile ilgili yanıta bakın.


12
JavaScript'te, değişkenleri açıklamayı unutmayın:var tuple, name, age;
Šime Vidas

3
var name=tuple[0], age=tuple[1]; Biraz daha yazı yazmak ama çirkin bir abartı olabilir.
Brent Bradburn

Yanıtlar:


123

Javascript 1.7 , esasen peşinde olduğunuz şeyi yapmanıza izin veren yıkılmış atama ekledi .

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

5
Bu, standartlara dayalı bir javascript değil, Mozilla'ya özgü uzantılardır.
ninjagecko

14
@ninjagecko: "JavaScript" Mozilla'nın uygulamasıdır ve yıkıcı atamalar gelecek ecmascript standardının bir parçası olacaktır
Bergi

66
Şimdi aslında ES6'nın bir parçası.
Pier Paolo Ramon

10
Birkaç yıl verildiğinde cevabım teknik olarak doğru hale geldi ancak hem düzeltmeye hem de yardımcı olmaya yardımcı olmadı. Yaşasın!
pc1oad1etter

49

Bunu çirkin bir şekilde yapmalısın. Eğer varsa gerçekten böyle bir şey istiyorum, sen kontrol edebilirsiniz CoffeeScript bu ve daha piton gibi görünmesi diğer özellikleri bir sürü vardır, (üzgünüm böyle gerçekten bir reklam gibi ses yapma, ama ben için.)


Hmm, bu oldukça ilginç, sadece bu senaryoya kendim girdim, çünkü JavaScript bariz bir demet desteği sağlamıyor gibi görünüyor ve yoğun bir işlevsel programlama döneminden gelince, demetlere olan ihtiyacı geliştiriyorsunuz. Ayrıca bunu yeni buldum, ancak işe yarayıp yaramadığından emin değilim, sadece tuple desteği açısından da iyi görünüyordu: cs.umd.edu/projects/PL/arrowlets/api-tuples.xhtml . CoffeeScript'e kesinlikle bakacağım.
9codeMan9

29

Benzer bir şey yapabilirsiniz:

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

ve ardından öznitelikler olarak ada ve yaşa bakın

tuple.name 
tuple.age 

5
Olumsuz oy vermeyeceğim ama teknik olarak bu yanlış. Nesne bildirildikten sonra tuple.name ve tuple.age değerlerini yine de değiştirebilirsiniz (yani mutasyona uğratabilirsiniz). Tanım olarak değişmez türler, tanımlandıktan sonra değiştirilemez. Hem parametrelerin hem de değerlerinin yalnızca bir kez bildirilebildiği salt okunur türler gibidirler.
Evan Plaice

4
@EvanPlaice Eğer değişkenlik bir sorunsa, kullanabilirsiniz Object.freeze(), yani:tuple = Object.freeze({ name:'Bob', age:14 })
canon

@canon Kabul ediyorum, muhtemelen bu konudaki tek kabul edilebilir / doğru yaklaşım bu. Ne yazık ki, mcm'nin cevabı nesneyi dondurmuyor, bu yüzden hala değiştirilebilir.
Evan Plaice

@EvanPlaice Değişkenlik konusunun nereden geldiğini anlamıyorum - orijinal Python örneğinde dizeler değişmez değildir!
Daniel Buckmaster

@DanielBuckmaster Python'da bir liste ile bir tuple arasındaki fark, bir listenin değişebilir, oysa bir tuple değildir. Docs.python.org/2/tutorial/… bakın . Tuples, JavaScript'te yerel olarak desteklenmez çünkü oluşturulduktan sonra nesnede Object.freeze () öğesini çağırmadığınız sürece tüm JS veri yapıları değiştirilebilir.
Evan Plaice

27

Bu "tuple" özelliğine EcmaScript2015'te imha etme adı verilir ve yakında güncel tarayıcılar tarafından desteklenecektir. Şimdilik sadece Firefox ve Chrome bunu destekliyor .

Ama hey, bir aktarıcı kullanabilirsiniz .

Kod python kadar güzel görünür:

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

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

2
Gelecekteki okuyucular için: Bu özellik chrome 49'dan beri (Mozilla belgelerine göre) desteklenmektedir. Uyumluluğu Mozilla belgelerini kullanarak da kontrol edebilirsiniz: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
Jamie

14

Dondurulmuş bir dizi bir python tuple ile aynı şekilde davranır:

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

Süslü olun ve bir sınıf tanımlayın

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

Bugün tüm en yeni tarayıcılarda çalışıyor.


Bunu bir kurucuya ayarlayamaz mısın? Sabit değişmez, değil mi?
Mark A

3
Hayır. Sabit yeniden atanamaz. Const tuple = ["Jim", 35]; tuple = ["James", 35]. Const tuple = ["Jim", 35]; tuple [0] = "James"; Bu nedenle değişmez değildir.
Matthew James Davis

6

Tuples, JavaScript'te desteklenmez

Değişmez bir liste arıyorsanız, Object.freeze () bir diziyi değişmez yapmak için kullanılabilir.

Object.freeze () yöntemi bir nesneyi dondurur: yani yeni özelliklerin ona eklenmesini engeller; mevcut mülklerin kaldırılmasını engeller; ve mevcut özelliklerin veya bunların numaralandırılabilirliğinin, yapılandırılabilirliğinin veya yazılabilirliğinin değiştirilmesini engeller. Özünde, nesne etkili bir şekilde değişmez hale getirilir. Yöntem dondurulmakta olan nesneyi döndürür.

Kaynak: Mozilla Geliştirici Ağı - Object.freeze ()

Her zamanki gibi bir dizi atayın, ancak 'Object.freeze () kullanarak kilitleyin

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

Değerleri normal bir dizi gibi kullanın (python çoklu atama desteklenmez)

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

Yeni bir değer atamayı dene

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

Ama değer değişmedi

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

Bir yandan not olarak, umarım Tuples ES6'da birinci sınıf destek alır. Gerçek doğal demet (yani heterojen dizi) da hızı artıracaktır.
Evan Plaice

5

Maalesef bu demet atama sözdizimini (ECMA | Java) Komut Dosyasında kullanamazsınız.

DÜZENLEME: Mozilla / JS 1.7'ye bağlı biri - bu, tarayıcılar arası çalışmaz, ancak bu gerekli değilse, cevabınız var.


3

Bunun gerçek hayatta kullanılması amaçlanmamıştır, sadece ilginç bir egzersizdir. Bkz . JavaScript eval işlevini kullanmak neden kötü bir fikirdir? detaylar için.

Satıcıya özel uzantılara başvurmadan elde edebileceğiniz en yakın şey budur:

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

Yardımcı işlev:

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(',');
}

Keyfi kapsamda çalıştığının kanıtı:

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

eval Safari'de desteklenmiyor.


5
1 süper zeki olduğu için, hiç gerçek hayatta bu kullanmayan :-p olsa
Jamund Ferguson

3

Bakan'ın cevabına bir güncelleme olarak, artık bunu es2015 ile yapabilirsiniz:

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


Bunu ES2015'ten önce yapamamış olmanızın bir nedeni yok ... Ayrıca bu OP'nin sorusuna cevap vermiyor, imha etmek istedi
assembly_wizard

3

Javascript'te de bir demet türüne sahip olabilirsiniz. Sadece daha yüksek dereceli işlevlerle tanımlayın (akademik terim Kilise kodlamasıdır):

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

Lütfen Tuplebunun normal bir kurucu olarak kullanılmadığını unutmayın . Çözüm hiçbir şekilde prototip sistemine değil, yalnızca daha yüksek dereceli işlevlere dayanır.

Tuplelar Arraygibi kullanılan tupleların avantajları nelerdir ? Kilise kodlu tuplelar, tasarım gereği değişmezdir ve dolayısıyla mutasyonların neden olduğu yan etkileri önler. Bu, daha sağlam uygulamalar oluşturmaya yardımcı olur. Ek olarak, Arraybir koleksiyon türü (ör. [a]) Olarak s ve çeşitli türlerdeki ilgili veriler (ör. ) Olarak tuplları birbirinden ayıran kod hakkında mantık yürütmek daha kolaydır (a, b).


1

İşte basit bir Javascript Tuple uygulaması:

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.

Bu bir 2 tuple, ancak, örneğimi 3,4,5,6 vb. Dizileri destekleyecek şekilde değiştirebilirsiniz.


Aslında bu bir t-uple değil, bir çift.
Pier Paolo Ramon

tupleÖrneğin halen değişken, bu yüzden teknik olarak bir tanımlama grubu değil. Geçirmez değişiklik için tuple.Item1 = "Steve"daha sonra console.log()çıkış.
Evan Plaice

1
Bunu bulduğunuz için teşekkürler. Tuple'ı değişmez hale getirmek için örneği değiştirdim.
Faris Zacina

Keyfi bir uzunluğu desteklemek için bunu nasıl değiştirirsiniz?
aij

Bu OP'nin sorusuna yanıt vermiyor, imha edilmesini istedi
assembly_wizard

-1

Matthew James Davis'in Python tuple yöntemlerine eklenen cevabının bir versiyonu:

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)


-1

Oldukça iyi çalışan bir demet uygulaması yaptım. Bu çözüm, dizi bozmanın yanı sıra temel tür kontrolüne izin verir.

const Tuple = (function() {
    function Tuple() {
        // Tuple needs at least one element
        if (arguments.length < 1) {
            throw new Error('Tuple needs at least one element');
        }

        const args = { ...arguments };

        // Define a length property (equal to the number of arguments provided)
        Object.defineProperty(this, 'length', {
            value: arguments.length,
            writable: false
        });

        // Assign values to enumerable properties
        for (let i in args) {
            Object.defineProperty(this, i, {
                enumerable: true,
                get() {
                    return args[+i];
                },
                // Checking if the type of the provided value matches that of the existing value
                set(value) {
                    if (typeof value !== typeof args[+i]) {
                        throw new Error('Cannot assign ' + typeof value + ' on ' + typeof args[+i]);
                    }

                    args[+i] = value;
                }
            });
        }

        // Implementing iteration with Symbol.iterator (allows for array destructuring as well for...of loops)
        this[Symbol.iterator] = function() {
            const tuple = this;

            return {
                current: 0,
                last: tuple.length - 1,
                next() {
                    if (this.current <= this.last) {
                        let val = { done: false, value: tuple[this.current] };
                        this.current++;
                        return val;
                    } else {
                        return { done: true };
                    }
                }
            };
        };

        // Sealing the object to make sure no more values can be added to tuple
        Object.seal(this);
    }

    // check if provided object is a tuple
    Tuple.isTuple = function(obj) {
        return obj instanceof Tuple;
    };

    // Misc. for making the tuple more readable when printing to the console
    Tuple.prototype.toString = function() {
        const copyThis = { ...this };
        const values = Object.values(copyThis);
        return `(${values.join(', ')})`;
    };

    // conctat two instances of Tuple
    Tuple.concat = function(obj1, obj2) {
        if (!Tuple.isTuple(obj1) || !Tuple.isTuple(obj2)) {
            throw new Error('Cannot concat Tuple with ' + typeof (obj1 || obj2));
        }

        const obj1Copy = { ...obj1 };
        const obj2Copy = { ...obj2 };

        const obj1Items = Object.values(obj1Copy);
        const obj2Items = Object.values(obj2Copy);

        return new Tuple(...obj1Items, ...obj2Items);
    };

    return Tuple;
})();

const SNAKE_COLOR = new Tuple(0, 220, 10);

const [red, green, blue] = SNAKE_COLOR;
console.log(green); // => 220


Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.