将返回的 JSON 对象属性转换为(较低的第一个)camelCase
Posted
技术标签:
【中文标题】将返回的 JSON 对象属性转换为(较低的第一个)camelCase【英文标题】:Convert returned JSON Object Properties to (lower first) camelCase 【发布时间】:2012-10-07 13:32:11 【问题描述】:我从这样的 API 返回 JSON:
Contacts: [ GivenName: "Matt", FamilyName: "Berry" ]
为了与我的代码风格保持一致(camelCase - 小写首字母),我想转换数组以生成以下内容:
contacts: [ givenName: "Matt", familyName: "Berry" ]
最简单/最好的方法是什么?创建一个新的联系人对象并遍历返回数组中的所有联系人?
var jsonContacts = json["Contacts"],
contacts= [];
_.each(jsonContacts , function(item)
var contact = new Contact( item.GivenName, item.FamilyName );
contacts.push(contact);
);
或者我可以映射原始数组或以某种方式对其进行转换吗?
【问题讨论】:
如果你真的很想在 javascript 中使用驼峰式表示法,你将不得不映射传入的对象。 api.jquery.com/jQuery.map 应该可以帮助您进行映射。 【参考方案1】:如果您使用lodash 代替下划线,则可以这样做:
_.mapKeys(obj, (v, k) => _.camelCase(k))
这会将TitleCase
和snake_case
都转换为camelCase
。请注意,它不是递归的。
【讨论】:
注意:这不适用于嵌套属性,仅适用于***键。【参考方案2】:这是一个可靠的递归函数,可以正确地对 JavaScript 对象的所有属性进行驼峰式命名:
function toCamel(o)
var newO, origKey, newKey, value
if (o instanceof Array)
return o.map(function(value)
if (typeof value === "object")
value = toCamel(value)
return value
)
else
newO =
for (origKey in o)
if (o.hasOwnProperty(origKey))
newKey = (origKey.charAt(0).toLowerCase() + origKey.slice(1) || origKey).toString()
value = o[origKey]
if (value instanceof Array || (value !== null && value.constructor === Object))
value = toCamel(value)
newO[newKey] = value
return newO
测试:
var obj =
'FirstName': 'John',
'LastName': 'Smith',
'BirthDate': new Date(),
'ArrayTest': ['one', 'TWO', 3],
'ThisKey':
'This-Sub-Key': 42
console.log(JSON.stringify(toCamel(obj)))
输出:
"firstName":"John",
"lastName":"Smith",
"birthDate":"2017-02-13T19:02:09.708Z",
"arrayTest": [
"one",
"TWO",
3
],
"thisKey":
"this-Sub-Key":42
【讨论】:
我建议检查o.hasOwnProperty(key)
并将if (typeof value === "object")
更改为if (value !== null && typeof value === "object")
。如果不检查value !== null
,此函数会将空值转换为空对象。
好的提示 - 将添加这些提示。
如果 o 是 Date 对象(或任何没有自己属性的对象),这将丢失值信息。结帐演示codepen.io/anon/pen/EPqZLY?editors=1010
一年后,我终于花时间正确检测非普通对象属性(如Date
)。我们检查构造函数是否为Object
,然后再对其余部分进行驼峰式封装。
@brandonscript 如果任何属性是一个数组,它实际上会丢失,你只检查主对象是否是一个数组。此行缺少检查它是否为数组:if (value !== null && value.constructor === Object)
这是您失败的示例:plnkr.co/edit/tEBYU3pQmJJZyl84CFo5 修复了检查数组:plnkr.co/edit/78gDwcLChAOT31XGoLG6【参考方案3】:
你可以用这个递归函数来做到这一点(使用 lodash 和 ES6):
import camelCase from 'lodash';
const camelizeKeys = (obj) =>
if (Array.isArray(obj))
return obj.map(v => camelizeKeys(v));
else if (obj != null && obj.constructor === Object)
return Object.keys(obj).reduce(
(result, key) => (
...result,
[camelCase(key)]: camelizeKeys(obj[key]),
),
,
);
return obj;
;
测试:
const obj =
'FirstName': 'John',
'LastName': 'Smith',
'BirthDate': new Date(),
'ArrayTest': ['one', 'TWO', 3],
'ThisKey':
'This-Sub-Key': 42
console.log(JSON.stringify(camelizeKeys(obj)))
输出:
"firstName": "John",
"lastName": "Smith",
"birthDate": "2018-05-31T09:03:57.844Z",
"arrayTest":[
"one",
"TWO",
3
],
"thisKey":
"thisSubKey": 42
【讨论】:
完全符合我的需要。谢谢。 非常感谢。工作正常。我会用_.isPlainObject(obj)
替换obj !== null && obj.constructor === Object
完美转换嵌套对象(包括数组和诸如此类),这里不能说其他一些答案。 +1
这似乎是唯一适用于所有情况的答案
这应该是公认的答案——最新的【参考方案4】:
要将普通对象的键从 snake_case
更改为 camelCase
递归请尝试以下操作
(使用Lodash):
function objectKeysToCamelCase(snake_case_object)
var camelCaseObject = ;
_.forEach(
snake_case_object,
function(value, key)
if (_.isPlainObject(value) || _.isArray(value)) // checks that a value is a plain object or an array - for recursive key conversion
value = objectKeysToCamelCase(value); // recursively update keys of any values that are also objects
camelCaseObject[_.camelCase(key)] = value;
)
return camelCaseObject;
;
在这个PLUNKER中测试
注意:也递归地作用于数组中的对象
【讨论】:
@Kody - 仅为您更新代码和 plunker - 现在适用于嵌套在数组中的对象(JSON 或其他):-) plunker 真的为我节省了很多时间。 我将 _.isPlainObject(value) 更改为 _.isObject(value),它对我有用,谢谢! 注意,如果你传递给它,这会展平一个数组 - 并返回一个对象 正如@GalBracha 所说,这似乎不会将数组保留为数组。我一起破解了这个:plnkr.co/edit/OnLVNqq7dHW1T3ukuyd1【参考方案5】:使用 lodash 和 ES6,这会将所有键递归替换为驼峰式:
const camelCaseKeys = (obj) =>
if (!_.isObject(obj))
return obj;
else if (_.isArray(obj))
return obj.map((v) => camelCaseKeys(v));
return _.reduce(obj, (r, v, k) =>
return
...r,
[_.camelCase(k)]: camelCaseKeys(v)
;
, );
;
【讨论】:
我最喜欢的解决方案 如果我们有这样的对象,这将失败: [ hello: 0 , hello: null , hello: undefined , hello: false ] 它会返回 [hello: , hello: , hello: ), hello: ] 可以通过添加 if (obj === 0 || obj === null || obj === 来修复未定义 || obj === false) 返回 obj; 很好,速记版本与扩展版本不一致。我已更新为仅显示扩展答案【参考方案6】:这是axios interceptors 的一个很好的用例
基本上,定义一个客户端类并附加一个转换请求/响应数据的前/后拦截器。
export default class Client
get(url, data, successCB, catchCB)
return this._perform('get', url, data, successCB, catchCB);
post(url, data, successCB, catchCB)
return this._perform('post', url, data, successCB, catchCB);
_perform(method, url, data, successCB, catchCB)
// https://github.com/axios/axios#interceptors
// Add a response interceptor
axios.interceptors.response.use((response) =>
response.data = toCamelCase(response.data);
return response;
, (error) =>
error.data = toCamelCase(error.data);
return Promise.reject(error);
);
// Add a request interceptor
axios.interceptors.request.use((config) =>
config.data = toSnakeCase(config.data);
return config;
, (error) =>
return Promise.reject(error);
);
return axios(
method: method,
url: API_URL + url,
data: data,
headers:
'Content-Type': 'application/json',
,
).then(successCB).catch(catchCB)
这是一个gist,其中包含一个使用 React/axios 的更长示例。
【讨论】:
IMO - 这可能是最好的答案,使用拦截器是一种非常干净的方法,可以将所有 snake_case 键移动到 camelCase 并将代码保存在一个健全的地方,tyvm【参考方案7】:只用驼峰
humps.camelize('hello_world');
humps.camelizeKeys(object, options); // will work through entire object
https://www.npmjs.com/package/humps
【讨论】:
很棒的图书馆推荐【参考方案8】:使用 lodash,你可以这样做:
export const toCamelCase = obj =>
return _.reduce(obj, (result, value, key) =>
const finalValue = _.isPlainObject(value) || _.isArray(value) ? toCamelCase(value) : value;
return ...result, [_.camelCase(key)]: finalValue ;
, );
;
【讨论】:
【参考方案9】:有一个很好的 npm 模块。 https://www.npmjs.com/package/camelcase-keys
npm install camelcase-keys
const camelcaseKeys = require( "camelcase-keys" );
camelcaseKeys( Contacts: [ GivenName: "Matt", FamilyName: "Berry" ] , deep: true );
将返回...
contacts: [ givenName: "Matt", familyName: "Berry" ]
【讨论】:
我特别喜欢这个答案,因为整个包约为 9kb。在反应框架内对我来说很好,感谢您的回答!【参考方案10】:好吧,我接受了挑战,并认为我想通了:
var firstToLower = function(str)
return str.charAt(0).toLowerCase() + str.slice(1);
;
var firstToUpper = function(str)
return str.charAt(0).toUpperCase() + str.slice(1);
;
var mapToJsObject = function(o)
var r = ;
$.map(o, function(item, index)
r[firstToLower(index)] = o[index];
);
return r;
;
var mapFromJsObject = function(o)
var r = ;
$.map(o, function(item, index)
r[firstToUpper(index)] = o[index];
);
return r;
;
// Map to
var contacts = [
GivenName: "Matt",
FamilyName: "Berry"
,
GivenName: "Josh",
FamilyName: "Berry"
,
GivenName: "Thomas",
FamilyName: "Berry"
];
var mappedContacts = [];
$.map(contacts, function(item)
var m = mapToJsObject(item);
mappedContacts.push(m);
);
alert(mappedContacts[0].givenName);
// Map from
var unmappedContacts = [];
$.map(mappedContacts, function(item)
var m = mapFromJsObject(item);
unmappedContacts.push(m);
);
alert(unmappedContacts[0].GivenName);
Property converter (jsfiddle)
诀窍是将对象作为对象属性的数组来处理。
【讨论】:
这是一个不错的解决方案!两个警报都是大写的,但我明白了。整件事困扰着我,如果我这样做并且不更改它,它会弄乱我所有的模型/控制器。它只是一种痛苦。谢谢。 现在是驼峰式的属性名称,请注意映射中的.givenName
和映射中的.GivenName
...确认属性已更改名称而不是值。跨度>
这是一个设计决策,这是拥有动态语言的难点。对自己应用某些约定以保持一切正常:)【参考方案11】:
以下是您可能想尝试的方便库: https://www.npmjs.com/package/camelize2
您只需使用npm install --save camelize2
安装它,然后
const camelize = require('camelize2')
const response =
Contacts: [ GivenName: "Matt", FamilyName:"Berry" ]
const camelizedResponse = camelize(response)
【讨论】:
【参考方案12】:这个解决方案基于上面的纯js解决方案,使用loadash和如果作为参数传递则保留一个数组并且只改变Keys强>
function camelCaseObject(o)
let newO, origKey, value
if (o instanceof Array)
newO = []
for (origKey in o)
value = o[origKey]
if (typeof value === 'object')
value = camelCaseObject(value)
newO.push(value)
else
newO =
for (origKey in o)
if (o.hasOwnProperty(origKey))
newO[_.camelCase(origKey)] = o[origKey]
return newO
// Example
const obj = [
'my_key': 'value',
'Another_Key':'anotherValue',
'array_key':
['me_too':2]
]
console.log(camelCaseObject(obj))
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.js"></script>
【讨论】:
该函数只在处理数组时是递归的。一旦遇到非数组对象,它只会对***属性键进行驼峰式处理。 这不是纯 JS 解决方案。这需要 lodash 所以从技术上讲它不是纯 JS...【参考方案13】:我需要一个接受数组或对象的通用方法。这就是我正在使用的(我借用了 KyorCode 的 firstToLower()
实现):
function convertKeysToCamelCase(obj)
if (!obj || typeof obj !== "object") return null;
if (obj instanceof Array)
return $.map(obj, function(value)
return convertKeysToCamelCase(value);
);
var newObj = ;
$.each(obj, function(key, value)
key = key.charAt(0).toLowerCase() + key.slice(1);
if (typeof value == "object" && !(value instanceof Array))
value = convertKeysToCamelCase(value);
newObj[key] = value;
);
return newObj;
;
示例调用:
var contact = GivenName: "Matt", FamilyName:"Berry" ;
console.log(convertKeysToCamelCase(contact));
// logs: Object givenName="Matt", familyName="Berry"
console.log(convertKeysToCamelCase([contact]));
// logs: [Object givenName="Matt", familyName="Berry"]
console.log(convertKeysToCamelCase("string"));
// logs: null
console.log(contact);
// logs: Object GivenName="Matt", FamilyName="Berry"
【讨论】:
在$.each
循环内,你应该添加if (value instanceof Array) value = convertKeysToCamelCase(value);
以确保数组的值也可以被映射
好点。数组有效,但非数组对象无效。我编辑以支持这些。【参考方案14】:
通过 lodash 和一些 es6+ 功能迎接挑战 这是我使用 reduce 函数的实现。
function deeplyToCamelCase(obj)
return _.reduce(obj, (camelCaseObj, value, key) =>
const convertedDeepValue = _.isPlainObject(value) || _.isArray(value)
? deeplyToCamelCase(value)
: value;
return ...camelCaseObj, [_.camelCase(key)] : convertedDeepValue ;
, );
;
【讨论】:
【参考方案15】:使用 lodash ...
function isPrimitive (variable)
return Object(variable) !== variable
function toCamel (variable)
if (isPrimitive(variable))
return variable
if (_.isArray(variable))
return variable.map(el => toCamel(el))
const newObj =
_.forOwn(variable, (value, key) => newObj[_.camelCase(key)] = toCamel(value))
return newObj
【讨论】:
【参考方案16】:类似于@brandonscript 的解决方案,但采用更多 ES6 功能的方式:
const camelCaseString = str => (
(str.charAt(0).toLowerCase() + str.slice(1) || str).toString()
);
const objectToCamelCase = val =>
if (typeof val != 'object' || val === null)
return val;
if (val instanceof Array)
return val.map(objectToCamelCase);
return Object.keys(val)
.filter(prop => val.hasOwnProperty(prop))
.map(prop => ([camelCaseString(prop)]: objectToCamelCase(val[prop])))
.reduce((prev, current) => (...prev, ...current))
;
// Example:
let converted = objectToCamelCase(UserId: 1, Hobbies: [Id: 1, Label: "Read"], Name: "John Doe");
console.log(converted)
【讨论】:
【参考方案17】:使用来自https://plnkr.co/edit/jtsRo9yU12geH7fkQ0WL?p=preview 的引用更新了代码 这通过将数组保持为数组(您可以使用 map 对其进行迭代)来处理带有数组的对象以及其中的对象等等。
function snakeToCamelCase(snake_case_object)
var camelCaseObject;
if (isPlainObject(snake_case_object))
camelCaseObject = ;
else if(isArray(snake_case_object))
camelCaseObject = [];
forEach(
snake_case_object,
function(value, key)
if (isPlainObject(value) || isArray(value))
value = snakeToCamelCase(value);
if (isPlainObject(camelCaseObject))
camelCaseObject[camelCase(key)] = value;
else if(isArray(camelCaseObject))
camelCaseObject.push(value);
)
return camelCaseObject;
【讨论】:
【参考方案18】:这是我的看法;比brandoncode的实现更具可读性和更少的嵌套,并且有更多空间来处理像Date
(顺便说一下没有处理)或null
这样的边缘情况:
function convertPropertiesToCamelCase(instance)
if (instance instanceof Array)
var result = [];
for (var i = 0; i < instance.length; i++)
result[i] = convertPropertiesToCamelCase(instance[i]);
return result;
if (typeof instance != 'object')
return instance;
var result = ;
for (var key in instance)
if (!instance.hasOwnProperty(key))
continue;
result[key.charAt(0).toLowerCase() + key.substring(1)] = convertPropertiesToCamelCase(instance[key]);
return result;
【讨论】:
很好,但是当翻译成 TypeScript 时,这会丢弃用 getter 和 setter 定义的属性。【参考方案19】:以goredwards 答案为基础(未正确处理数组字段)
function objectKeysToCamelCase(snake_case_object)
let camelCaseObject =
_.forEach(
snake_case_object,
function(value, key)
if (_.isPlainObject(value))
value = objectKeysToCamelCase(value)
else if (_.isArray(value))
value = value.map(v => _.isPlainObject(v) ? objectKeysToCamelCase(v) : v)
camelCaseObject[_.camelCase(key)] = value
,
)
return camelCaseObject
【讨论】:
【参考方案20】:这是我找到的代码,虽然没有经过全面测试,但值得分享。 它比其他答案更具可读性,不确定性能。
测试它http://jsfiddle.net/ms734bqn/1/
const toCamel = (s) =>
return s.replace(/([-_][a-z])/ig, ($1) =>
return $1.toUpperCase()
.replace('-', '')
.replace('_', '');
);
;
const isArray = function (a)
return Array.isArray(a);
;
const isObject = function (o)
return o === Object(o) && !isArray(o) && typeof o !== 'function';
;
const keysToCamel = function (o)
if (isObject(o))
const n = ;
Object.keys(o)
.forEach((k) =>
n[toCamel(k)] = keysToCamel(o[k]);
);
return n;
else if (isArray(o))
return o.map((i) =>
return keysToCamel(i);
);
return o;
;
【讨论】:
【参考方案21】:将对象键转换为深的驼峰式。
import _ from 'lodash';
export function objectKeysToCamelCase(entity)
if (!_.isObject(entity)) return entity;
let result;
result = _.mapKeys(entity, (value, key) => _.camelCase(key));
result = _.mapValues(result, (value) => objectKeysToCamelCase(value));
return result;
【讨论】:
以上是关于将返回的 JSON 对象属性转换为(较低的第一个)camelCase的主要内容,如果未能解决你的问题,请参考以下文章
如何利用fastjson将JSON格式的字符串转换为Map,再返回至前端成为js对象