在对象中查找所有Date类型的属性,并将相同的属性从字符串转换为克隆对象中的Date对象

时间:2019-01-21 19:02:04

标签: javascript jquery date recursion

我有一个复杂的物体

{
  "original": {
    "assetName": "2669937-cherry-blossoms-wallpapers.jpg",
    "tags": "",
    "id": 5834
  },
  "uploadState": {
    "status": 3
  },
  "file": {
    "isThumbnailable": false,
    "name": "2669937-cherry-blossoms-wallpapers.jpg",
    "tags": []
  },
  "customFields": [{
    "customFormApplicationId": 2014,
    "customFieldId": 1017,
    "referenceId": 0,
    "referenceType": 0,
    "label": "qaa",
    "orderId": 0,
    "type": 1,
    "value": "",
    "defaultValue": "",
    "properties": "MULTILINE:false|WATERMARK_TEXT:",
    "dateCreated": "0001-01-01T00:00:00",
    "isRequired": true,
    "$$hashKey": "object:22760",
    "requiredValueSet": false
  }, {
    "customFormApplicationId": 2014,
    "customFieldId": 1018,
    "referenceId": 0,
    "referenceType": 0,
    "label": "ddd",
    "orderId": 1,
    "type": 3,
    "properties": "MULTILINE:true|WATERMARK_TEXT:|VISIBLE_LINES:5|DISPLAY_TYPE:1|DATE_FORMAT:1|TIME_FORMAT:1",
    "dateCreated": "0001-01-01T00:00:00",
    "isRequired": true,
    "$$hashKey": "object:22761",
    "isSet": true,
    "value": "",
    "requiredValueSet": false
  }, {
    "customFormApplicationId": 2014,
    "customFieldId": 2017,
    "referenceId": 0,
    "referenceType": 0,
    "label": "drop",
    "orderId": 2,
    "type": 2,
    "value": "",
    "defaultValue": "",
    "properties": "MULTILINE:true|WATERMARK_TEXT:|VISIBLE_LINES:5|ITEMS:v1,v2,v3|DISPLAY_TYPE:1",
    "dateCreated": "0001-01-01T00:00:00",
    "isRequired": false,
    "$$hashKey": "object:22762"
  }],
  "$$hashKey": "object:16951"
}

具有动态结构。

我必须深度克隆对象,并且正在使用此方法

var clone = $.parseJSON(JSON.stringify(original));

这是唯一实际起作用的东西,因此无法使用其他方法。 问题是Date对象转换为字符串 因此,而不是

"dateCreated": Mon Jan 21 2019 13:45:06 GMT-0500 (Eastern Standard Time)
__proto__: Object,

我有"dateCreated":"2019-01-21T18:45:06.696Z"

要将其转换回我使用的日期

clone.dateCreated = new Date(original.dateCreated )

问题是我的对象非常复杂并且具有动态属性,所以我不知道对象的结构。

我需要编写将在原始对象上运行的函数,并检查每个属性,如果该属性为Date类型,然后克隆到相同的属性并将该字符串转换为Date

该函数应如何显示?两个关键问题:

1-运行原始对象的所有属性并检查类型   2-在克隆对象中找到相同的属性

假设它们具有相同的结构

我使用的是ES5,没有lodash或下划线库

2 个答案:

答案 0 :(得分:0)

如果您坚持使用JSON.parse(JSON.stringify),则以下内容将在生成的对象上递归并将所有与正则表达式匹配的字符串值转换为Dates。

它仅处理JSON处理产生的可能类型,如果您需要更复杂的内容,则只需要更多的 is…测试和以下逻辑。希望评论足够。

// Parse ISO 8601 date YYYY-MM-DDTHH:mm:ssZ
// Z is optional, indicates UTC
// Parses '0001' as 0001 not 1901
function toDate(s) {
  var b = s.split(/\D/);
  var d = new Date(0);
  if (/z$/i.test(s)) {
    d.setUTCFullYear(b[0], b[1]-1, b[2]);
    d.setUTCHours(b[3], b[4], b[5], b[6]||0);
    return d;
  } else {
    d.setFullYear(b[0], b[1]-1, b[2]);
    d.setHours(b[3], b[4], b[5], b[6]||0);
    return d;
  }
}

// Recurse over objects, if any property value is a string that
// matches the ISO 8601 pattern /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z?$/
// convert it to a Date object
function stringsToDates(obj) {

  // Simple isObject and isArray functions
  let isObj = value => Object.prototype.toString.call(value) == '[object Object]';
  let isArr = value => Array.isArray(value);
  // Test if value is string date, object or array and convert, recurse or ignore
  let resolveValue = (value, key, obj) => {
    if (typeof value == 'string' && re.test(value)) {
      obj[key] = toDate(value);
    } else if (isArr(value) || isObj(value)) {
      go(value);
    }
  }

  // Regular expression for ISO date string
  var re = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z?$/;
  
  // Recursive function looking for strings matching re
  function go(obj) {

    if (isArr(obj)) {
      obj.forEach((value, i, arr) => resolveValue(value, i, arr));
      
    } else if (isObj(obj)) {
      Object.keys(obj).forEach(key => resolveValue(obj[key], key, obj))
    }
  }
  return go(obj);
}

// Test data
var x = {
  aDate: '0001-01-01T00:00:00',  // level 0
  bool: true,
  obj: {arr: ['0002-01-01T00:00:00z', 'string', false]}, // level 2
  arr: ['0003-01-01T00:00:00', null, true, []], // level 1
  obj1: {
    nest: {
      deep: {
        string: 'foo',
        date0: '0004-01-01T00:00:00Z',  // level 4
        date1: '0005-01-01T00:00:00',  // level 4
        arr1: ['0006-01-01T00:00:00z', NaN, {}]  // level 5
      }
    }
  }
}

// Do conversion
stringsToDates(x);
console.log(x);

答案 1 :(得分:0)

我最终做了对象的angular.copy,由于File对象不能正确复制,我只是用原始File覆盖了它。

var clone = angular.copy(original);
clone.file = original.file