Scorrere le proprietà degli oggetti


2040

var obj = {
    name: "Simon",
    age: "20",
    clothing: {
        style: "simple",
        hipster: false
    }
}

for(var propt in obj){
    console.log(propt + ': ' + obj[propt]);
}

In che modo la variabile proptrappresenta le proprietà dell'oggetto? Non è un metodo o una proprietà incorporati. Perché viene fornito con ogni proprietà nell'oggetto?


11
if (typeof(obj[propt]) === 'object') {/ * Fallo di nuovo * /}
noob il

13
Beh, mi dispiace davvero per questa domanda. So che cos'è un loop, non riuscivo a capire come "scorrere le proprietà degli oggetti", che ora penso sia stato cancellato. Inoltre, mi hanno raccomandato "JavaScript Step by Step 2nd Edition - Steve Suehring a scuola.
Rafay,

242
Questa è una bella domanda per i principianti. Aggiungo che ho 15 anni di esperienza professionale con altre lingue e avevo bisogno di questa risposta. Avrei più 2000 se potessi.
Nathan C. Tresch,

60
Pazzo, ma vengo su questa pagina ogni pochi mesi per anni per riapprendere la sintassi su come farlo. Non mi preoccupo di ricordare come farlo ... Ricordo solo che questa pagina è sempre qui su SO.
HDaveva il

14
Questa è la pagina più strana che abbia mai visto su StackOverflow. Se leggi attentamente la domanda, solo una risposta inizia persino a tentare di rispondere a ciò che viene effettivamente chiesto e ha un punteggio di -6. La risposta con il punteggio più alto, che è stata accettata, non solo non risponde, ma è semplicemente sbagliata.

Risposte:


2426

L'iterazione delle proprietà richiede questo hasOwnPropertycontrollo aggiuntivo :

for (var prop in obj) {
    if (Object.prototype.hasOwnProperty.call(obj, prop)) {
        // do stuff
    }
}

È necessario perché il prototipo di un oggetto contiene proprietà aggiuntive per l'oggetto che sono tecnicamente parte dell'oggetto. Queste proprietà aggiuntive sono ereditate dalla classe di oggetti base, ma sono comunque proprietà di obj.

hasOwnProperty controlla semplicemente se si tratta di una proprietà specifica di questa classe e non ereditata dalla classe di base.


È anche possibile richiamare hasOwnPropertyl'oggetto stesso:

if (obj.hasOwnProperty(prop)) {
    // do stuff
}

Ma questo fallirà se l'oggetto ha un campo non correlato con lo stesso nome:

var obj = { foo: 42, hasOwnProperty: 'lol' };
obj.hasOwnProperty('foo');  // TypeError: hasOwnProperty is not a function

Ecco perché è più sicuro chiamarlo attraverso Object.prototype:

var obj = { foo: 42, hasOwnProperty: 'lol' };
Object.prototype.hasOwnProperty.call(obj, 'foo');  // true

21
@BT Secondo la documentazione di Mozilla : "Se si desidera considerare solo le proprietà associate all'oggetto stesso e non i suoi prototipi, utilizzare getOwnPropertyNames o eseguire un controllo hasOwnProperty (è possibile utilizzare anche PropertyIsEnumerable)".
davidmdem,

3
Qual è esattamente il punto di chiamare object.hasOwnProperty()? Il fatto che propertyabbia un valore qualunque non implica che sia dentro object?
Alex S

6
Perché, Alex S, il prototipo di un oggetto contiene proprietà aggiuntive per l'oggetto che sono tecnicamente parte dell'oggetto. Sono ereditati dalla classe di oggetti base, ma sono comunque proprietà. hasOwnProperty verifica semplicemente se si tratta di una proprietà specifica di questa classe e non ereditata dalla classe base. Una buona spiegazione: brianflove.com/2013/09/05/javascripts-hasownproperty-method
Kyle Richter

87
Sento che dovrei menzionare, tuttavia, che Object.keys (obj) è ora una soluzione molto migliore per ottenere le chiavi dell'oggetto stesso. Link alla documentazione di Mozilla: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
Kyle Richter,

9
Manca un'informazione importante. propertyè una stringa qui, avrebbe dovuto essere chiamata propertyName. Altrimenti può causare confusione per i neofiti di JS come me, ovvero cosa fare all'interno di if.
Neolisk,

1136

A partire da JavaScript 1.8.5 è possibile utilizzare Object.keys(obj)per ottenere una matrice di proprietà definite sull'oggetto stesso (quelle che restituiscono true per obj.hasOwnProperty(key)).

Object.keys(obj).forEach(function(key,index) {
    // key: the name of the object key
    // index: the ordinal position of the key within the object 
});

Questo è meglio (e più leggibile) rispetto all'utilizzo di un ciclo for-in.

È supportato su questi browser:

  • Firefox (Gecko): 4 (2.0)
  • Chrome: 5
  • Internet Explorer: 9

Vedere Developer Network Mozilla Object.keys () di riferimento 's per informazioni addizionali sulla consegna.



3
E se hai bisogno di supporto per i vecchi browser, puoi usare questo polyfill
KyleMit,

27
In ambienti che supportano questo costrutto linguistico, questo metodo consente di chiamare Array.foreach: Object.keys(myObject).forEach(function(key,index) { //key = the name of the object key //index = the ordinal position of the key within the object });
Todd Price

4
@ AJ_83 Non c'è un buon modo per uscire da un forEach (). Usa alcuni () in questo caso e ritorna true per rompere
Daniel Z.

11
perché è più leggibile del for-in? for candidate in candidateStatus... mi sembra leggibile
Jona,

309

Ragazze e ragazzi siamo nel 2019 e non abbiamo molto tempo per scrivere ... Quindi facciamo questo fantastico nuovo ECMAScript 2016:

Object.keys(obj).forEach(e => console.log(`key=${e}  value=${obj[e]}`));

17
In che modo differisce dalla risposta di Danny R?
Krillgar,

27
È un oneliner e utilizza la mappa anziché forOach. E anche l'appuntamento console.log è forse interessante per alcune persone.
Frank Roth,

Satly, quello non funziona quando obj=window.performance.memory: - / Dove come for infa. vale a direvar obj = window.performance.memory; for( key in obj ) console.log( 'key=' + key + ' val=' + obj[key] );
Michaelangel007,

2
window.performance.memoryè supportato solo da Chrome e Object.keys(obj)restituisce un array vuoto. Questo non ha nulla a che fare con .map.
Frank Roth,

Nel caso in cui qualcuno non volesse preoccuparsi di ristrutturare questo single-liner per fare più di una cosa alla volta e, ho pubblicato questo riassunto. Fondamentalmente è proprio come la maggior parte delle implementazioni di hash e utilizza ( (key) => (value) )invece di { key => value }, ma se non hai dovuto occupartene prima, potrebbe aiutarti a visualizzarlo meglio: gist.github.com/the-nose-knows/9f06e745a56ff20519707433e28a4fa8
kayleeFrye_onDeck

216

È il for...in statement( MDN , specifiche ECMAScript ).

Si può leggere come " PER ogni proprietà IN l' objoggetto, assegnare ad ogni struttura al PROPT variabili, a sua volta".


1
Grazie mille, ora lo capisco. Mi sbattevo la testa, sfogliavo libri e Google.
Rafay,

21
D'accordo con @RightSaidFred, l' inoperatore e l' foristruzione non sono coinvolti a tutti, la for-indichiarazione rappresenta una produzione grammaticale da solo: for ( LeftHandSideExpression in Expression ),for ( var VariableDeclarationNoIn in Expression )
CMS

2
Strano questa risposta ha così tanti voti positivi, soprattutto perché questi commenti popolari sembrano contraddirla.
Doug Molineux,

9
Perché questo è contrassegnato come risposta? È probabilmente il meno utile in questo thread ..
computrius

3
La risposta meno utile? Dipende da cosa pensi che l'OP stesse chiedendo; quando ho letto la domanda per la prima volta, mi è sembrato sconcertato il divertimento sul meccanismo con cui una variabile può essere usata per ispezionare le proprietà di un oggetto, e che questa risposta spiega eloquentemente (nonostante il termine "for-in"). La domanda "Perché viene fuori con ogni proprietà" che vedo potrebbe implicare che l'OP stava cercando hasOwnProperty ma non lo sa, ma penso sia più probabile che questo fosse ciò che l'OP voleva sapere e ha erroneamente accettato un corretto rispondere a una domanda diversa. :-)
Bumpy

157

Nelle implementazioni aggiornate di ES, è possibile utilizzare Object.entries:

for (const [key, value] of Object.entries(obj)) { }

o

Object.entries(obj).forEach(([key, value]) => ...)

Se vuoi semplicemente scorrere i valori, usa Object.values:

for (const value of Object.values(obj)) { }

o

Object.values(obj).forEach(value => ...)

questa sarebbe la soluzione migliore (object.entries ...), ma non posso usarla. Quando vuoi farlo più volte e non puoi supportarlo nel tuo framework, puoi usare il polyfill in questa pagina: developer.mozilla.org/nl/docs/Web/JavaScript/Reference/…
Mario,

Il terzo suggerimento è ottimo se solo i valori delle proprietà. Eccezionale!
Ginzburg,


27

Se il tuo ambiente supporta ES2017 , consiglierei Object.entries :

Object.entries(obj).forEach(([key, value]) => {
  console.log(`${key} ${value}`);
});

Come mostrato nella documentazione di Mozillas Object.entries () :

Il metodo Object.entries () restituisce una matrice delle coppie di proprietà [chiave, valore] di un determinato oggetto, nello stesso ordine di quello fornito da un ciclo for ... in (la differenza è che enumera un ciclo for-in proprietà anche nella catena di prototipi).

Fondamentalmente con Object.entries possiamo rinunciare al seguente passaggio aggiuntivo che è necessario con il più vecchio per ... in loop:

// This step is not necessary with Object.entries
if (object.hasOwnProperty(property)) {
  // do stuff
}

22

jquery ti permette di farlo ora:

$.each( obj, function( key, value ) {
  alert( key + ": " + value );
});

1
$.each({foo:1, length:0, bar:2}, function(k,v){console.log(k,v)})$ .each non è adatto per gli oggetti. Se un oggetto ha una proprietà length e il suo valore è zero, l'intero oggetto viene trattato come se fosse un array vuoto.
Bob Stein

Dettagli sul perché penso che questo sia un approccio invitante per i bug .
Bob Stein,

21

La risposta di Dominik è perfetta, preferisco solo farlo in questo modo, poiché è più pulito da leggere:

for (var property in object) {
    if (!object.hasOwnProperty(property)) continue;

    // Do stuff...
}

Dovrebbe essere in Objectmaiuscolo o no, no?
Jonathan

18

Le risposte di cui sopra sono un po 'fastidiose perché non spiegano cosa fai all'interno del ciclo for dopo esserti assicurato che sia un oggetto: NON LO ACCEDI DIRETTAMENTE! In realtà ti viene consegnato solo il CHIAVE che devi applicare all'OBJ:

var obj = {
  a: "foo",
  b: "bar",
  c: "foobar"
};

// We need to iterate the string keys (not the objects)
for(var someKey in obj)
{
  // We check if this key exists in the obj
  if (obj.hasOwnProperty(someKey))
  {
    // someKey is only the KEY (string)! Use it to get the obj:
    var myActualPropFromObj = obj[someKey]; // Since dynamic, use [] since the key isn't literally named "someKey"

    // NOW you can treat it like an obj
    var shouldBeBar = myActualPropFromObj.b;
  }
}

Tutto questo è sicuro per ECMA5. Funziona anche nelle versioni JS come Rhino;)


15

Per aggiungere l'utilizzo di ES2015 di Reflect.ownKeys(obj) e l'iterazione di sulle proprietà tramite un iteratore.

Per esempio:

let obj = { a: 'Carrot', b: 'Potato', Car: { doors: 4 } };

può essere ripetuto da

// logs each key
Reflect.ownKeys(obj).forEach(key => console.log(key));

Se desideri iterare direttamente sui valori delle chiavi di un oggetto, puoi definire un iterator , proprio come gli iteratori predefiniti di JavaScipts per stringhe, array, array digitati, Map e Set.

JS tenterà di eseguire l'iterazione tramite la proprietà iteratore predefinita, che deve essere definita come Symbol.iterator.

Se vuoi essere in grado di iterare su tutti gli oggetti, puoi aggiungerlo come prototipo di Object:

Object.prototype[Symbol.iterator] = function*() { 
    for(p of Reflect.ownKeys(this)){ yield this[p]; }
}

Ciò consentirebbe di scorrere i valori di un oggetto con un ciclo for ... of, ad esempio:

for(val of obj) { console.log('Value is:' + val ) }

Attenzione : al momento di scrivere questa risposta (giugno 2018) tutti gli altri browser, tranne IE, supportano i generatori e l' for...ofiterazione tramiteSymbol.iterator


Sebbene non stiate effettivamente rispondendo alla domanda del PO, questo mi è stato molto utile, non sapevo ancora di Reflect.
Michiel

15
if(Object.keys(obj).length) {
    Object.keys(obj).forEach(key => {
        console.log("\n" + key + ": " + obj[key]);
    });
}

// *** Explanation line by line ***

// Explaining the bellow line
// It checks if obj has at least one property. Here is how:
// Object.keys(obj) will return an array with all keys in obj
// If there is no keys in obj, it will return empty array = []
// Then it will get it's length, if it has at least one element,
// it's bigger than 0 which evaluates to true and the bellow 
// code will be executed.
// Else means it's length = 0 which evaluates to false
// NOTE: you can use Object.hasOwnProperty() instead of Object.keys(obj).length
if(Object.keys(obj).length) {

    // Explaining the bellow line
    // Just like in the previous line, this returns an array with
    // all keys in obj (because if code execution got here, it means 
    // obj has keys.) 
    // Then just invoke built-in javascript forEach() to loop
    // over each key in returned array and calls a call back function 
    // on each array element (key), using ES6 arrow function (=>)
    // Or you can just use a normal function ((key) { blah blah }).
    Object.keys(obj).forEach(key => {

        // The bellow line prints out all keys with their 
        // respective value in obj.
        // key comes from the returned array in Object.keys(obj)
        // obj[key] returns the value of key in obj
        console.log("\n" + key + ": " + obj[key]);
    });
}

3
Ciao, potresti aggiungere ulteriori informazioni sulla tua risposta, fornendo solo il codice non aiuta.
Nicolas,

Ciao @Nicolas Ho aggiunto una spiegazione riga per riga al codice. Fammi sapere se non è ancora chiaro
Fouad Boukredine,

Poiché forEach salta i valori vuoti , penso che potresti sbarazzarti del se e fare semplicemente Object.keys(obj).forEach(e => console.log(`key=${e} value=${obj[e]}`));come la risposta di Frank Roth.
Darkproduct,

12

Il ciclo for ... in rappresenta ciascuna proprietà di un oggetto perché è proprio come un ciclo for. Hai definito propt nel ciclo for ... in facendo:

    for(var propt in obj){
alert(propt + ': ' + obj[propt]);
}

Un ciclo for ... in scorre le proprietà enumerabili di un oggetto. Qualunque sia la variabile definita o inserita nel ciclo for ... in, cambia ogni volta che passa alla proprietà successiva che itera. La variabile nel ciclo for ... in scorre le chiavi, ma il suo valore è il valore della chiave. Per esempio:

    for(var propt in obj) {
      console.log(propt);//logs name
      console.log(obj[propt]);//logs "Simon"
    }

Puoi vedere come la variabile differisce dal valore della variabile. Al contrario, un ciclo for ... of fa il contrario.

Spero che questo possa essere d'aiuto.


11
let obj = {"a": 3, "b": 2, "6": "a"}

Object.keys(obj).map((item) => {console.log("item", obj[item])})

// a
// 3
// 2

1
Come menzionato in altri commenti, forEachè più appropriato qui, poiché mapè destinato a restituire un nuovo array con i risultati della chiamata al blocco di codice su ogni iterazione. Ma siamo interessati solo agli effetti collaterali di ogni iterazione, non al valore restituito, quindi non abbiamo bisogno di quel nuovo array che mapci dà.
Danny,


10

Puoi usare Lodash. La documentazione

var obj = {a: 1, b: 2, c: 3};
_.keys(obj).forEach(function (key) {
    ...
});

10
Perché mai questa "risposta" ha 10 voti? Non riesce completamente a rispondere alla domanda. Sto iniziando a perdere fiducia nell'intelligence sullo sviluppatore medio di JS.
Developerbmw,

1
@developerbmw Capisco che l'utilizzo delle funzionalità ES6 è più corretto, ma ho risposto un anno fa. Per favore, condividi i tuoi pensieri con noi quando hai un minuto.
viktarpunko,

1
L'idea è quella di concentrarsi maggiormente sui metodi nativi, invece di suggerire all'utente di aggiungere una libreria di 10000 righe alla propria pagina. Non fraintendetemi, mi piace usare Lodash ma c'è un tempo e un posto per farlo e non è questo.

9

Il tuo forciclo sta iterando su tutte le proprietà dell'oggetto obj. proptè definito nella prima riga del ciclo for. È una stringa che è un nome di una proprietà objdell'oggetto. Nella prima iterazione del ciclo, proptsarebbe "nome".


9

Gli oggetti in JavaScript sono raccolte di proprietà e possono quindi essere inseriti in un ciclo per ogni istruzione.

Dovresti pensare obja una raccolta di valori chiave.


! con l'importante differenza che questi "elenchi di proprietà" possono avere nomi come chiavi, mentre i normali array JS possono avere solo numeri come chiavi.
Qqwy,

9

Oggi è possibile convertire un oggetto JS standard in un oggetto iterabile semplicemente aggiungendo un metodo Symbol.iterator. Quindi puoi usare un for ofloop e accedere direttamente ai suoi valori o persino usare un operatore spread sull'oggetto. Freddo. Vediamo come possiamo farcela:

var o = {a:1,b:2,c:3},
    a = [];
o[Symbol.iterator] = function*(){
                       var ok = Object.keys(this);
                            i = 0;
                       while (i < ok.length) yield this[ok[i++]];
                     };
for (var value of o) console.log(value);
// or you can even do like
a = [...o];
console.log(a);


1
Modo interessante per farlo. Grazie per la function*scoperta!
Benj,

5

Se si esegue Node , consiglierei:

Object.keys(obj).forEach((key, index) => {
    console.log(key);
});

5

Mentre la risposta più votata è corretta, ecco un caso d'uso alternativo, ad esempio se stai iterando su un oggetto e vuoi creare un array alla fine. Usa .mapinvece diforEach

const newObj = Object.keys(obj).map(el => {
    //ell will hold keys 
   // Getting the value of the keys should be as simple as obj[el]
})

4

Aggiungendo anche il modo ricorsivo:

function iterate(obj) {
    // watch for objects we've already iterated so we won't end in endless cycle
    // for cases like var foo = {}; foo.bar = foo; iterate(foo);
    var walked = [];
    var stack = [{obj: obj, stack: ''}];
    while(stack.length > 0)
    {
        var item = stack.pop();
        var obj = item.obj;
        for (var property in obj) {
            if (obj.hasOwnProperty(property)) {
                if (typeof obj[property] == "object") {
                  // check if we haven't iterated through the reference yet
                  var alreadyFound = false;
                  for(var i = 0; i < walked.length; i++)
                  {
                    if (walked[i] === obj[property])
                    {
                      alreadyFound = true;
                      break;
                    }
                  }
                  // new object reference
                  if (!alreadyFound)
                  {
                    walked.push(obj[property]);
                    stack.push({obj: obj[property], stack: item.stack + '.' + property});
                  }
                }
                else
                {
                    console.log(item.stack + '.' + property + "=" + obj[property]);
                }
            }
        }
    }
}

Uso:

iterate({ foo: "foo", bar: { foo: "foo"} }); 

1
@faiz - vedi i miei commenti, è una protezione contro l'essere bloccati in un ciclo infinito quando si cammina attraverso oggetti ricorrenti che hanno riferimenti ciclici
Ondrej Svejdar

3

Quello che fa per..in loop è che crea una nuova variabile (var someVariable) e quindi memorizza ciascuna proprietà dell'oggetto dato in questa nuova variabile (someVariable) una per una. Pertanto, se si utilizza il blocco {}, è possibile eseguire l'iterazione. Considera il seguente esempio.

var obj = {
     name:'raman',
     hobby:'coding',
     planet:'earth'
     };

for(var someVariable in obj) {
  //do nothing..
}

console.log(someVariable); // outputs planet

Valorizzare questo, data la sua semplicità. Nel mio caso d'uso ho bisogno di controllare tutti gli attributi in un oggetto per valori non validi: NaN, null, non definiti (erano punti su un grafico e questi valori impedivano al grafico di disegnare). Per ottenere il valore anziché il nome, nel loop lo faresti semplicemente obj[someVariable]. Forse il motivo per cui è stato sottoposto a downvoting così tanto è perché non è ricorsivo. Quindi questa non sarebbe una soluzione adeguata se si dispone di un oggetto altamente strutturato.
Katharine Osborne,

@KatharineOsborne o forse è perché la seguente frase è un po 'enigmatica: "Quindi se usi il blocco {}, puoi iterare." Il codice dice più del testo.
bvdb,

3

Qui sto iterando ogni nodo e creando nomi di nodo significativi. Se noti, instanceOf Array e instanceOf Object fa praticamente la stessa cosa (nella mia applicazione, sto dando una logica diversa però)

function iterate(obj,parent_node) {
    parent_node = parent_node || '';
    for (var property in obj) {
        if (obj.hasOwnProperty(property)) {
            var node = parent_node + "/" + property;
            if(obj[property] instanceof Array) {
                //console.log('array: ' + node + ":" + obj[property]);
                iterate(obj[property],node)
            } else if(obj[property] instanceof Object){
                //console.log('Object: ' + node + ":" + obj[property]);
                iterate(obj[property],node)
            }
            else {
                console.log(node + ":" + obj[property]);
            }
        }
    }
}

nota - Sono ispirato dalla risposta di Ondrej Svejdar. Ma questa soluzione ha prestazioni migliori e meno ambigue


3

Fondamentalmente si desidera eseguire il ciclo attraverso ogni proprietà nell'oggetto.

JSFiddle

var Dictionary = {
  If: {
    you: {
      can: '',
      make: ''
    },
    sense: ''
  },
  of: {
    the: {
      sentence: {
        it: '',
        worked: ''
      }
    }
  }
};

function Iterate(obj) {
  for (prop in obj) {
    if (obj.hasOwnProperty(prop) && isNaN(prop)) {
      console.log(prop + ': ' + obj[prop]);
      Iterate(obj[prop]);
    }
  }
}
Iterate(Dictionary);

obj(prop)<- TypeError: obj non è una funzione
le_m

@le_m il mio male. Devo eliminare accidentalmente l' hasOwnPropertyattributo. Dovrebbe funzionare ora.
HovyTech,

2

Voglio aggiungere le risposte sopra, perché potresti avere intenzioni diverse da Javascript. Un oggetto JSON e un oggetto Javascript sono cose diverse e potresti voler scorrere le proprietà di un oggetto JSON usando le soluzioni proposte in precedenza e quindi rimanere sorpreso.

Supponiamo di avere un oggetto JSON come:

var example = {
    "prop1": "value1",
    "prop2": [ "value2_0", value2_1"],
    "prop3": {
         "prop3_1": "value3_1"
    }
}

Il modo sbagliato di scorrere le sue "proprietà":

function recursivelyIterateProperties(jsonObject) {
    for (var prop in Object.keys(example)) {
        console.log(prop);
        recursivelyIterateProperties(jsonObject[prop]);
    }
}

Potreste essere sorpresi di vedere la registrazione della console 0, 1ecc quando l'iterazione attraverso le proprietà di prop1e prop2e diprop3_1 . Tali oggetti sono sequenze e gli indici di una sequenza sono proprietà di quell'oggetto in Javascript.

Un modo migliore per iterare ricorsivamente attraverso le proprietà di un oggetto JSON sarebbe innanzitutto verificare se quell'oggetto è una sequenza o meno:

function recursivelyIterateProperties(jsonObject) {
    for (var prop in Object.keys(example)) {
        console.log(prop);
        if (!(typeof(jsonObject[prop]) === 'string')
            && !(jsonObject[prop] instanceof Array)) {
                recursivelyIterateProperties(jsonObject[prop]);

            }

     }
}

1

Per affinare ulteriormente la risposta accettata vale la pena di notare che se si un'istanza dell'oggetto con un var object = Object.create(null)poi object.hasOwnProperty(property)attiverà una TypeError. Quindi, per essere al sicuro, dovresti chiamarlo dal prototipo in questo modo:

for (var property in object) {
    if (Object.prototype.hasOwnProperty.call(object, property)) {
        // do stuff
    }
}

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.