Oculte certos valores na saída de JSON.stringify ()

86

É possível excluir certos campos de serem incluídos na string json?

Aqui está um pseudo código

var x = {
    x:0,
    y:0,
    divID:"xyz",
    privateProperty1: 'foo',
    privateProperty2: 'bar'
}

Eu quero excluir privateProperty1 e privateproperty2 de aparecerem na string json

Então pensei, posso usar a função substituidor de stringify

function replacer(key,value)
{
    if (key=="privateProperty1") then retun "none";
    else if (key=="privateProperty2") then retun "none";
    else return value;
}

e no stringify

var jsonString = json.stringify(x,replacer);

Mas no jsonString ainda vejo como

{...privateProperty1:value..., privateProperty2:value }

Eu gostaria da string sem as propriedades privadas nelas.

Nilesh
fonte
Possível duplicata: stackoverflow.com/questions/208105/…
Jared Farrish
4
em vez de retornar "nenhum" retorna indefinido.
JoeyRobichaud
1
Eu vi essa pergunta e não quero excluir propriedades, pois isso afeta meu aplicativo atual. Estou tentando salvar o objeto em um arquivo e o aplicativo ainda possui o objeto ativo, portanto, excluir uma propriedade o tornará inútil. Outra opção é clonar o objeto, excluir campos e, em seguida, sequenciar o objeto clone.
Nilesh
1
Ei Joe, isso foi ótimo. O indefinido fez o truque. Obrigado. Vou atualizar a pergunta
Nilesh

Respostas:

101

Os documentos do Mozilla dizem para retornar undefined(em vez de "none"):

http://jsfiddle.net/userdude/rZ5Px/

function replacer(key,value)
{
    if (key=="privateProperty1") return undefined;
    else if (key=="privateProperty2") return undefined;
    else return value;
}

var x = {
    x:0,
    y:0,
    divID:"xyz",
    privateProperty1: 'foo',
    privateProperty2: 'bar'
};

alert(JSON.stringify(x, replacer));

Aqui está um método de duplicação, caso você decida seguir esse caminho (conforme seu comentário).

http://jsfiddle.net/userdude/644sJ/

function omitKeys(obj, keys)
{
    var dup = {};
    for (var key in obj) {
        if (keys.indexOf(key) == -1) {
            dup[key] = obj[key];
        }
    }
    return dup;
}

var x = {
    x:0,
    y:0,
    divID:"xyz",
    privateProperty1: 'foo',
    privateProperty2: 'bar'
};

alert(JSON.stringify(omitKeys(x, ['privateProperty1','privateProperty2'])));

EDIT - eu mudei a tecla de função na função inferior para evitar que seja confuso.

Jared Farrish
fonte
33

Outra boa solução: (requer sublinhado)

x.toJSON = function () {
    return _.omit(this, [ "privateProperty1", "privateProperty2" ]);
};

O benefício dessa solução é que qualquer pessoa que chamar JSON.stringify em x terá resultados corretos - você não precisa alterar as chamadas JSON.stringify individualmente.

Versão sem sublinhado:

x.toJSON = function () {
    var result = {};
    for (var x in this) {
        if (x !== "privateProperty1" && x !== "privateProperty2") {
            result[x] = this[x];
        }
    }
    return result;
};
Curtis Yallop
fonte
Eu voto por essa abordagem porque acho que é mais elegante.
Romeo Sierra
18

Você pode usar a função nativa defineProperty de Object:

var data = {a: 10};
Object.defineProperty(data, 'transient', {value: 'static', writable: true});
data.transient = 'dasda';
console.log(JSON.stringify(data)); //{"a":10}
Miroslaw Dylag
fonte
12
Essa resposta funciona porque o enumerablevalor desse descritor de propriedade é falso.
Soul_Master de
Nota: Não funciona se os dados são uma matriz e se deseja ocultar o enésimo elemento dele.
Alex Szücs,
3

Maneira mais fácil de fazer.

  1. Crie uma variável e atribua um array vazio. Isso faz com que o objeto seja o protótipo do array.
  2. Adicione teclas não numéricas neste objeto.
  3. Serialize este objeto usando JSON.stringify
  4. Você verá que nada é serializado a partir deste objeto.

~~~

var myobject={
  a:10,
  b:[]
};

myobject.b.hidden1 = 'hiddenValue1';
myobject.b.hidden2 = 'hiddenValue2';

//output of stringify 
//{
//    "a": 10,
//    "b": []
//}

~~~

http://www.markandey.com/2015/07/how-to-hide-few-keys-from-being-being.html

Markandey Singh
fonte
2

Object.create é outra solução próxima da solução defineProperty (as propriedades são definidas da mesma maneira), mas dessa forma você define as propriedades a serem expostas desde o início. Desta forma, você pode expor apenas as propriedades que deseja definindo o enumerablevalor da propriedade como verdadeiro (falso por padrão), JSON.stringify está ignorando propriedades não enumeráveis, a desvantagem é que essa propriedade também ficará oculta ao usar for-in loop no objeto ou funções como Object.keys.

var x = Object.create(null, {
    x: {value:0, enumerable: true}, 
    y:{value: 0, enumerable: true}, 
    divID: {value: 'xyz', enumerable: true}, 
    privateProperty1: {value: 'foo'}, 
    privateProperty2: {value: 'bar'}
});
JSON.stringify(x)
//"{"x":0,"y":0,"divID":"xyz"}"
Matan Hafuta
fonte
2

Nota para a resposta de Miroslaw Dylag : A propriedade definida deve ser sua própria propriedade. Caso contrário, iria falhar.

Não funciona:

class Foo {
}
Object.defineProperty(Foo.prototype, 'bar', { value: 'bar', writable: true });

const foo = new Foo();
foo.bar = 'baz';
alert(JSON.stringify(foo).indexOf('bar') === -1); // false (found)

Trabalho:

class Foo {
  constructor() {
    Object.defineProperty(this, 'bar', { value: 'bar', writable: true });
  }
}

const foo = new Foo();
foo.bar = 'baz';
alert(JSON.stringify(foo).indexOf('bar') === -1); // true (not found)
Audi Nugraha
fonte
1

Eu sei que esta já é uma questão respondida, mas gostaria de acrescentar algo ao usar objetos instatados.

Se você atribuí-lo usando uma função, ele não será incluído no resultado JSON.stringify ().

Para acessar o valor, chame-o também como uma função, terminando com ()

var MyClass = function(){
    this.visibleProperty1 = "sample1";
    this.hiddenProperty1 = function(){ return "sample2" };
}

MyClass.prototype.assignAnother = function(){
    this.visibleProperty2 = "sample3";
    this.visibleProperty3 = "sample4";
    this.hiddenProperty2 = function(){ return "sample5" };
}

var newObj = new MyClass();
console.log( JSON.stringify(newObj) );
// {"visibleProperty1":"sample1"}

newObj.assignAnother();
console.log( JSON.stringify(newObj) );
// {"visibleProperty1":"sample1","visibleProperty2":"sample3","visibleProperty3":"sample4"}

console.log( newObj.visibleProperty2 ); // sample3
console.log( newObj.hiddenProperty1() ); // sample2
console.log( newObj.hiddenProperty2() ); // sample5

Você também pode brincar com o conceito, mesmo quando não estiver em objetos instatados.

dragonjet
fonte
Isso funciona apenas se você não precisar definir o valor dessa propriedade.
Gabriel C
0
abstract class Hideable {
    public hidden = [];
    public toJSON() {
        var result = {};
        for (var x in this) {
            if(x == "hidden") continue;
            if (this.hidden.indexOf(x) === -1) {
                result[x] = this[x];
            }
        }
        return result;
    };
}
Carlos Arturo Alaniz
fonte
0

você pode fazer isso facilmente com ES2017

let {privateProperty1:exc1, privateProperty2:exc2, ...foo} = {
    x:0,
    y:0,
    divID:"xyz",
    privateProperty1: 'foo',
    privateProperty2: 'bar'
}

Aqui privateProperty1e privateProperty2são atribuídos exc1e em exc2conformidade. O restante é atribuído a uma foovariável recém-criada

Peja
fonte
0

Aqui está outra abordagem, embora sem suporte do Internet Explorer.

const privateProperties = ["privateProperty1", "privateProperty2"];
const excludePrivateProperties = (key, value) => privateProperties.includes(key) ? undefined : value;

const jsonString = JSON.stringify(x, excludePrivateProperties);
Mike Nikles
fonte
0

Esta é uma pergunta antiga, mas estou adicionando uma resposta, pois há uma maneira muito mais simples de lidar com isso. Passe uma matriz de strings que você deseja produzir no JSON.

var x = {
    x:0,
    y:0,
    divID:"xyz",
    privateProperty1: 'foo',
    privateProperty2: 'bar'
}

JSON.stringify(x, ["x", "y", "divID"]);

// This will output only x y and divID
// {"x":0,"y":0,"divID":"xyz"}

delp
fonte
0

Aqui está minha abordagem com o operador spread (...):

const obj = { name:"hello", age:42, id:"3942" };
const objWithoutId = { ...o, id: undefined }

const jsonWithoutId = JSON.stringify({...o, id:undefined});
Reinhard
fonte