简体   繁体   English

保留未定义的 JSON.stringify 否则将删除

[英]Preserving undefined that JSON.stringify otherwise removes

How do I preserve undefined values when doing JSON.stringify(hash) ?执行JSON.stringify(hash)时如何保留undefined的值?

Here's an example:这是一个例子:

var hash = {
  "name" : "boda",
  "email" : undefined,
  "country" : "africa"
};

var string = JSON.stringify(hash);

// > '{"name":"boda","country":"africa"}'

Email disappeared from JSON.stringify .电子邮件从JSON.stringify中消失了。

The JSON spec does not allow undefined values, but does allow null values. JSON 规范不允许undefined的值,但允许null值。

You can pass a replacer function to JSON.stringify to automatically convert undefined values to null values, like this:您可以将替换函数传递给JSON.stringify以自动将undefined的值转换为null值,如下所示:

var string = JSON.stringify(
  obj,
  function(k, v) { return v === undefined ? null : v; }
);

This works for undefined values inside arrays as well, as JSON.stringify already converts those to null .这也适用于数组中的未定义值,因为JSON.stringify已经将它们转换为null

You can preserve the key by converting to null since a valid JSON does not allow undefined ;您可以通过转换为null来保留密钥,因为有效的 JSON 不允许undefined

Simple one liner:简单的一个班轮:

JSON.stringify(obj, (k, v) => v === undefined ? null : v)

This should do the trick这应该可以解决问题

// Since 'JSON.stringify' hides 'undefined', the code bellow is necessary in
// order to display the real param that have invoked the error.
JSON.stringify(hash, (k, v) => (v === undefined) ? '__undefined' : v)
    .replace(/"__undefined"/g, 'undefined')

Use null instead of undefined .使用null而不是undefined

var hash = {
  "name" : "boda",
  "email" : null,
  "country" : "africa"
};

var string = JSON.stringify(hash);

> "{"name":"boda","email":null,"country":"africa"}"
function stringifyWithUndefined(obj, space) {
  const str = JSON.stringify(obj, (key, value) => value === undefined ? '__undefined__' : value, space);
  return str.replace(/"__undefined__"/g, 'undefined');
}

Example:例子:

const obj = {
  name: 'boda',
  email: undefined,
  country: 'africa'
};
console.log(stringifyWithUndefined(obj, 2));

Result:结果:

{
  "name": "boda",
  "email": undefined,
  "country": "africa"
}

Im reading between the lines here and guessing that you want to have the value undefined when you use JSON.parse?我在此处阅读并猜测您希望在使用 JSON.parse 时未定义该值?

If that is the case you could use the following:如果是这种情况,您可以使用以下内容:

var encodeUndefined = function(obj, undefinedPaths, path) {
  path = path || 'ROOT';
  for (var key in obj) {
    var keyPath = path + '.' + key;
    var value = obj[key];
    if (value === undefined) {
      undefinedPaths.push(keyPath);
    } else if (typeof value == "object" && value !== null) {
      encodeUndefined(obj[key], undefinedPaths, keyPath);
    }
  }
}

var stringifyAndPreserveUndefined = function(obj) {
  var undefinedPaths = [];
  //save all paths that have are undefined in a array.
  encodeUndefined((obj), undefinedPaths);
  return JSON.stringify({
    ROOT: obj,
    undefinedPaths: undefinedPaths
  }, function(k, v) { if (v === undefined) { return null; } return v; });
}

var parseAndRestoreUndefined = function(value) {
  var data = JSON.parse(value);
  var undefinedPaths = data.undefinedPaths;
  var obj = data.ROOT;
  //Restore all undefined values
  for (var pathIndex = 0; pathIndex < undefinedPaths.length; pathIndex++) {
    var pathParts = undefinedPaths[pathIndex].substring(5).split('.');
    var item = obj;
    for (var pathPartIndex = 0; pathPartIndex < pathParts.length - 1; pathPartIndex++) {
      item = item[pathParts[pathPartIndex]];
    }
    item[pathParts[pathParts.length - 1]] = undefined;
  }
  return obj;
}

var input = {
  test1: 'a',
  test2: 'b',
  test3: undefined,
  test4: {
    test1: 'a',
    test2: undefined
  }
};
var result = stringifyAndPreserveUndefined(input);
var result2 = parseAndRestoreUndefined(result);

stringifyAndPreserveUndefined will encode all undefined values in a array and when you call parseAndRestoreUndefined it will put them in the correct place again. stringifyAndPreserveUndefined将对数组中的所有未定义值进行编码,当您调用parseAndRestoreUndefined时,它将再次将它们放在正确的位置。

The one downside is the json will not look exactly like the object.一个缺点是 json 看起来与对象不完全相同。 In the example above it will turn into {"ROOT":{"test1":"a","test2":"b","test4":{"test1":"a"}},"undefinedPaths":["ROOT.test3","ROOT.test4.test2"]}在上面的例子中,它将变成{"ROOT":{"test1":"a","test2":"b","test4":{"test1":"a"}},"undefinedPaths":["ROOT.test3","ROOT.test4.test2"]}

JSON does not have an undefined value, but we could write a workaround: JSON 没有undefined的值,但我们可以编写一个解决方法:

Preserving nested undefined values保留嵌套的未定义值

I wrote 2 functions that internally uses JSON.stringify and JSON.parse and preserves nested undefined values using a value placeholder:我编写了 2 个内部使用JSON.stringifyJSON.parse的函数,并使用值占位符保留嵌套的undefined值:

Equivalent to JSON.stringify :相当于JSON.stringify

/**
 * Serialize a POJO while preserving nested `undefined` values.
 */
function serializePOJO(value, undefinedPlaceholder = "[undefined]") {
  const replacer = (key, value) => (value === undefined ? undefinedPlaceholder : value);
  return JSON.stringify(value, replacer);
}

Equivalent to JSON.parse :相当于JSON.parse

/**
 * Deserialize a POJO while preserving nested `undefined` values.
 */
function deserializePOJO(value, undefinedPlaceholder = "[undefined]") {
  const pojo = JSON.parse(value);
  if (pojo === undefinedPlaceholder) {
    return undefined;
  }

  // Function that walks through nested values
  function deepIterate(value, callback, parent, key) {
    if (typeof value === "object" && value !== null) {
      Object.entries(value).forEach(([entryKey, entryValue]) => deepIterate(entryValue, callback, value, entryKey));
    } else if (Array.isArray(value)) {
      value.forEach((itemValue, itemIndex) => deepIterate(itemValue, callback, value, itemIndex));
    } else if (parent !== undefined) {
      callback(value, parent, key);
    }
  }

  // Replaces `undefined` placeholders
  deepIterate(pojo, (value, parent, key) => {
    if (value === undefinedPlaceholder) {
      parent[key] = undefined;
    }
  });

  return pojo;
}

Usage:用法:

const source = {
    foo : undefined,
  bar : {
   baz : undefined
  }
};

const serialized = serializePOJO(source);
console.log("Serialized", serialized);
// '{"foo":"[undefined]","bar":{"baz":"[undefined]","qux":[1,"[undefined]",2]}}'

const deserialized = deserializePOJO(serialized);
console.log("Deserialized", deserialized);

Works with both object entries and array items.适用于对象条目和数组项。

The downside is that you have to choose an appropriate placeholder that will not be mistaken via a "real" source value.缺点是您必须选择一个合适的占位符,不会被“真实”源值弄错。 The placeholder is customizable via the optional undefinedPlaceholder argument.占位符可通过可选的undefinedPlaceholder参数进行自定义。

This is specially useful to store POJO in browser local storage ;)这对于将POJO存储在浏览器本地存储中特别有用;)

See also:也可以看看:

这将导致它打印为undefined ,但这是无效的 json,但它是有效的 JavaScript。

var string = JSON.stringify(obj, function(k,v){return v===undefined?"::undefined::":v}, 2).replace(new RegExp("\"::undefined::\"", 'g'), "undefined");

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM