检查对象是否可在JavaScript中序列化的可靠方法

时间:2015-06-01 17:49:06

标签: javascript json serialization

是否有已知的方法或库已经有一个帮助器来评估对象是否可以在JavaScript中序列化?

我尝试了以下内容,但它没有涵盖原型属性,因此它提供了误报:

_.isEqual(obj, JSON.parse(JSON.stringify(obj))

还有另一个lodash函数可能让我更接近真相,_.isPlainObject。但是,当_.isPlainObject(new MyClass())返回false时,_.isPlainObject({x: new MyClass()})会返回true,因此需要递归应用。

在我自己冒昧之前,是否有人知道一种已经可靠的方法来检查JSON.parse(JSON.stringify(obj))是否会实际产生与obj相同的对象?

3 个答案:

答案 0 :(得分:3)

function isSerializable(obj) {
  var isNestedSerializable;
  function isPlain(val) {
    return (typeof val === 'undefined' || typeof val === 'string' || typeof val === 'boolean' || typeof val === 'number' || Array.isArray(val) || _.isPlainObject(val));
  }
  if (!isPlain(obj)) {
    return false;
  }
  for (var property in obj) {
    if (obj.hasOwnProperty(property)) {
      if (!isPlain(obj[property])) {
        return false;
      }
      if (typeof obj[property] == "object") {
        isNestedSerializable = isSerializable(obj[property]);
        if (!isNestedSerializable) {
          return false;
        }
      }
    }
  }
  return true;
}

递归迭代所有给定的对象属性。它们可以是:

  • 普通对象(" 由Object构造函数创建的对象或[[Prototype]]为null的对象。" - 来自lodash文档)
  • 阵列
  • 字符串数字布尔
  • 未定义

传递obj内任何地方的任何其他值都会导致它被理解为"不可序列化"。

(老实说,我并不是绝对肯定的,我没有省略检查某些可序列化/不可序列化的数据类型,实际上我认为这取决于" serializable&#34的定义; - 欢迎任何意见和建议。)

答案 1 :(得分:2)

最后,我创建了自己的方法,利用了Underscore / Lodash的_.isPlainObject。我的功能最终类似于@bardzusny提出的,但我也发布了我的功能,因为我更喜欢简单/清晰。随意概述利弊。

var _ = require('lodash');

exports.isSerializable = function(obj) {
  if (_.isUndefined(obj) ||
      _.isNull(obj) ||
      _.isBoolean(obj) ||
      _.isNumber(obj) ||
      _.isString(obj)) {
    return true;
  }

  if (!_.isPlainObject(obj) &&
      !_.isArray(obj)) {
    return false;
  }

  for (var key in obj) {
    if (!exports.isSerializable(obj[key])) {
      return false;
    }
  }

  return true;
};

答案 2 :(得分:1)

这是@treznik解决方案的稍微更多的Lodashy ES6版本

    export function isSerialisable(obj) {

        const nestedSerialisable = ob => (_.isPlainObject(ob) || _.isArray(ob))  &&
                                         _.every(ob, isSerialisable);

        return  _.overSome([
                            _.isUndefined,
                            _.isNull,
                            _.isBoolean,
                            _.isNumber,
                            _.isString,
                            nestedSerialisable
                        ])(obj)
    }

测试

    describe.only('isSerialisable', () => {

        it('string', () => {
            chk(isSerialisable('HI'));
        });

        it('number', () => {
            chk(isSerialisable(23454))
        });

        it('null', () => {
            chk(isSerialisable(null))
        });

        it('undefined', () => {
            chk(isSerialisable(undefined))
        });


        it('plain obj', () => {
            chk(isSerialisable({p: 1, p2: 'hi'}))
        });

        it('plain obj with func', () => {
            chkFalse(isSerialisable({p: 1, p2: () => {}}))
        });


        it('nested obj with func', () => {
            chkFalse(isSerialisable({p: 1, p2: 'hi', n: { nn: { nnn: 1, nnm: () => {}}}}))
        });

        it('array', () => {
            chk(isSerialisable([1, 2, 3, 5]))
        });

        it('array with func', () => {
            chkFalse(isSerialisable([1, 2, 3, () => false]))
        });

        it('array with nested obj', () => {
            chk(isSerialisable([1, 2, 3, { nn: { nnn: 1, nnm: 'Hi'}}]))
        });

        it('array with newsted obj with func', () => {
            chkFalse(isSerialisable([1, 2, 3, { nn: { nnn: 1, nnm: () => {}}}]))
        });

    });

}