通过对camelCase属性进行分组来创建对象

时间:2016-04-02 17:23:45

标签: javascript arrays object

最近我发现我必须从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级的情况,但是我想让它适用于任何级别,因为我预见它会被需要,所以我可以公开发布代码。

5 个答案:

答案 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> 遍历对象的键,从而构建结果。我们将每个密钥分解为其组件,例如reducepersonNameperson。我们遍历这些组件,如果它们尚不存在则创建子对象。最后,我们将最终组件添加到最里面的子对象中,作为具有相关值的属性。

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字符串的解决方案。

&#13;
&#13;
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;
&#13;
&#13;