在 JSON.stringify()的输出中隐藏某些值

是否有可能将某些字段排除在 json 字符串之外?

下面是一些伪代码

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

我希望从 json 字符串中排除 private ateProperty1和 private ateProperty2

所以我想,我可以使用 stringify 替换函数

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

和在串联

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

但是在 jsonString 中,我仍然认为它是

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

我希望字符串中没有私有属性。

92835 次浏览

The Mozilla docs say to return undefined (instead of "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));

Here is a duplication method, in case you decide to go that route (as per your comment).

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 - I changed the function key in the bottom function to keep it from being confusing.

I know this is already an answered question, but I'd like to add something when using instatiated objects.

If you assign it using a function, it will not be included on the JSON.stringify() result.

To access the value, call it as a function as well, ending with ()

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

You can also play around with the concept even when not on instatiated objects.

Easier way to do.

  1. Create a variable and assign an empty array. This makes object to be the prototype of array.
  2. Add non numeric keys on this object.
  3. Serialize this object using JSON.stringify
  4. You will see that nothing is serialized from this object.

~~~

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

You can use native function defineProperty from Object:

var data = {a: 10};
Object.defineProperty(data, 'transient', {value: 'static', writable: true});
data.transient = 'dasda';
console.log(JSON.stringify(data)); //{"a":10}

Another good solution: (requires underscore)

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

The benefit of this solution is that anyone calling JSON.stringify on x will have correct results - you don't have to alter the JSON.stringify calls individually.

Non-underscore version:

x.toJSON = function () {
var result = {};
for (var x in this) {
if (x !== "privateProperty1" && x !== "privateProperty2") {
result[x] = this[x];
}
}
return result;
};

Object.create is another solution that is close to the defineProperty solution (properties are defined in the same way) but in this way you define the properties to expose from the beginning. In this way you can expose only the properties that you want by setting the property enumerable value to true (false by default), JSON.stringify is ignoring non-enumerable properties, the downside is that this property will also be hidden when using for-in loop on the object or functions like 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"}"

Note for Miroslaw Dylag's answer: The defined property should be its own property. Otherwise it would fail.

Doesn't work:

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)

Works:

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)
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;
};
}

you can do it easily with ES2017

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

Here privateProperty1 and privateProperty2 are assigned to exc1 and exc2 accordingly. The remainings are assigned to foo newly created variable

I've used toJSON solution based on a small library that i've written in order to get Typing at Runtime https://stackoverflow.com/a/55917109/4236151

Here's another approach, although without Internet Explorer support.

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


const jsonString = JSON.stringify(x, excludePrivateProperties);

This is an old question, but I'm adding an answer as there is a much simpler way to deal with this. Pass an array of strings that you wish to output in the 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"}

Here is my approach with the spread operator (...) :

const obj = {
name: "hello",
age: 42,
id: "3942"
};


const objWithoutId = { ...obj, id: undefined };


const jsonWithoutId = JSON.stringify(objWithoutId);


console.log(jsonWithoutId);

I subscribe to delp's Topic https://stackoverflow.com/a/62457745/14491024 This topic helped with my code

 JSON.stringify(GetMyContent[i], ["mdlPageName", "mdlAligen", "mdlOrderNumberHorizontal", "mdlPageId", "mdlOrderNumberVertical"])

That way I can pick attributes that I need:

    if (GetMyContent[i].mdlAligen == "Left") {


var getrownum = GetMyContent[i].mdlOrderNumberHorizontal;


if ($('.Left div.row:eq(' + (getrownum - 1) + ')').children().length > 0) {


$('.Left div.row:eq(' + (getrownum - 1) + ')').append("<div id=" + GetMyContent[i].mdlPageId + " class=\"border border-secondary col\"  " + "data-atrrib=" + JSON.stringify(GetMyContent[i], ["mdlPageName", "mdlAligen", "mdlOrderNumberHorizontal", "mdlPageId", "mdlOrderNumberVertical"]) + ">" + GetMyContent[i].mdlPageContentHtml + buttonEDI + "</div>");
}
else {
$('.Left div.row:last').html("<div id=" + GetMyContent[i].mdlPageId + " class=\"border border-secondary col\"  " + "data-atrrib=" + JSON.stringify(GetMyContent[i], ["mdlPageName", "mdlAligen", "mdlOrderNumberHorizontal", "mdlPageId", "mdlOrderNumberVertical"]) + ">" + GetMyContent[i].mdlPageContentHtml + buttonEDI + "</div>");


$(".Left .row:last").after($('.Left .row:eq(0)').clone().html(""));
}
}

In addition to toJSON and replacers. A simple fix would be to convert the variable to a 'static' variable. Since the static variables are added as prototype variables they won't come in the JSON string.

Caution: Please use this if the variable can be a static variable.

removes is an array of keys you want to omit. space is optional for pretty printing.

// typescript version
export function toJson<T>(me: T, removes?: (keyof T)[], space?: number): string {
return JSON.stringify(me, (k, v) => (removes?.some((r) => r === k) ? undefined : v), space);
}


// javascript version
export function toJson(me , removes , space) {
return JSON.stringify(me, (k, v) => (removes?.some((r) => r === k) ? undefined : v), space);
}

example

const data = {name: "ali" ,age: "80"};
console.log(toJson(data, ["age"]))


// output: {"name":"ali"}