最近我发现我必须从HTML标签的属性创建一个对象。我在AngularJS环境中执行此操作,因此带连字符的属性将转换为camelCase,但我也可以使用data-
属性和dataset
例如,我有:
<element person-name="Grant" animation-jump="123" />
给出了对象
{
"personName" : "Grant",
"animationJump" : "123"
{
我的问题是我想将该camelCase对象转换为结构化对象:
{
"person" : {
"name" : "Grant" },
"animation" : {
"jump" : "123" }
}
我已经创建了一个我的QUint单元测试的JSFiddle https://jsfiddle.net/gdt3bonw/ 它实际上适用于我想要的只有1级的情况,但是我想让它适用于任何级别,因为我预见它会被需要,所以我可以公开发布代码。
答案 0 :(得分:2)
我们将使用 <?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.world.bolandian.gcmtest">
<!-- To access Google+ APIs: -->
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.USE_CREDENTIALS" />
<!-- To retrieve the account name (email) as part of sign-in: -->
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<!-- To auto-complete the email text field in the login form with the user's emails -->
<uses-permission android:name="android.permission.READ_PROFILE" />
<uses-permission android:name="android.permission.READ_CONTACTS" />
<!-- [START gcm_permission] -->
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
<uses-sdk android:minSdkVersion="8" android:targetSdkVersion="17"/>
<uses-permission android:name="android.permission.WAKE_LOCK" />
<permission android:name="com.world.bolandian.gcmtest.permission.C2D_MESSAGE"
android:protectionLevel="signature" />
<uses-permission android:name="com.world.bolandian.gcmtest.permission.C2D_MESSAGE" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<receiver
android:name="com.google.android.gms.gcm.GcmReceiver"
android:exported="true"
android:permission="com.google.android.c2dm.permission.SEND" >
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
<category android:name="com.world.bolandian.gcmtest" />
</intent-filter>
</receiver>
<service
android:name=".MyGcmListenerService"
android:exported="false" >
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
</intent-filter>
</service>
<service
android:name=".MyInstanceIDListenerService"
android:exported="false">
<intent-filter>
<action android:name="com.google.android.gms.iid.InstanceID" />
</intent-filter>
</service>
<service
android:name=".RegistrationIntentService"
android:exported="false"></service>
</application>
</manifest>
遍历对象的键,从而构建结果。我们将每个密钥分解为其组件,例如reduce
到personName
和person
。我们遍历这些组件,如果它们尚不存在则创建子对象。最后,我们将最终组件添加到最里面的子对象中,作为具有相关值的属性。
name
答案 1 :(得分:1)
你不能以这种方式使用它,我也不认为这是一个逻辑提议。下面我解释为什么它不会。
obj[["animation","jump"]] = "123"
替换为
obj["animation"]["jump"] = "123"
并且一切都很好。
为什么我不支持你的想法?
答案 2 :(得分:1)
为什么首先需要将属性转换为camelCase ..?只是做
function arrayToStructuredObject(obj,props){
if (props.length){
obj[props[0]] = props.length > 1 ? {} : value;
arrayToStructuredObject(obj[props.shift()],props);
}
return obj;
}
var props = "animation-jump-tremendous-pinky".split("-"),
value = "123",
obj = {},
sobj = {};
sobj = arrayToStructuredObject(obj, props);
此外,我想提醒一下,只有在使用括号表示法的引用被预定义为对象时,才可以使用括号表示法来创建属性。如
var o1; // <- undefined
o1["myProp"] = 1; // Uncaught TypeError: Cannot set property 'myProp' of undefined
,而
var o2 = {}; // Object {}
o2["myProp"] = 1; // <- 1
然后再次
o2["myProp"]["myOtherProp"] = 2; // <- 2 but won't type coerce o2.myProp to Object
所以说到提议,我不确定是否直接在未定义的变量上使用括号表示法,因为另一个对象创建模式是否有意义。
在任何情况下,一个完整的解决方案都是
var inp = {"personName" : "Grant", "animationJump" : "123", "fancyGirlTakesARide" : "987"},
result = Object.keys(inp).reduce(function(p,c,i){
var props = c.replace(/[A-Z]/g, m => "-" + m.toLowerCase()).split("-");
return arrayToStructuredObject(p,props,inp[c])
},{});
function arrayToStructuredObject(obj,props,val){
if (props.length){
obj[props[0]] = props.length > 1 ? {} : val;
arrayToStructuredObject(obj[props.shift()],props,val);
}
return obj;
}
虽然我喜欢通过前瞻(/?=[A-Z]/
)分割camelCase道具的方法,但是它需要额外的工作来降低整个prop字符串数组,无论它们是否已经小写。所以我想这可能会稍快一些。 (..或者不是由于它的递归性质)
答案 3 :(得分:0)
这不是最佳解决方案,但在这种特殊情况下,您可以将数组转换为字符串,实际上可以使用数组作为键:
obj[["animation","Jump"].join()] = "123";
这适用于原始对象。
答案 4 :(得分:0)
使用Regex to split camel case字符串的解决方案。
var obj = { "animationsJump": "123", "animationsRun": "456", "animationsHide": "789", "personName": "Grant", "personPetsDog": "Snowy", "personPetsCat": "Snowball" },
newObject = {};
Object.keys(obj).forEach(function (k) {
var path = k.split(/(?=[A-Z])/).map(function (s) {
return s.toLowerCase();
}),
last = path.pop();
path.reduce(function (r, a) {
r[a] = r[a] || {};
return r[a];
}, newObject)[last] = obj[k];
});
document.write('<pre>' + JSON.stringify(newObject, 0, 4) + '</pre>');
&#13;