2015-01-21 19 views
5

"availability_meta.supplier.price" gibi nokta sınırlanmış dizeler olarak gelen bir grup nesne özniteliğim var ve record['availability_meta']['supplier']['price']'a karşılık gelen bir değer atamam gerekiyor.Javascript: Nokta ile sınırlandırılmış dizeleri iç içe nesne değerine dönüştürün

Her şey 3 seviye derin değil: çoğu yalnızca 1 seviye derin ve çoğu 3 seviyeden daha derindir.

Programatik olarak Javascript'te atamanın iyi bir yolu var mı? Örneğin, ben gerekir:

["foo.bar.baz", 1] // --> record.foo.bar.baz = 1 
["qux.qaz", "abc"] // --> record.qux.qaz = "abc" 
["foshizzle", 200] // --> record.foshizzle = 200 

ben beraber bir şeyler kesmek olabilir hayal, ama öyle önerilerinizi takdir ederiz akılda herhangi iyi bir algoritma yok. Bu işe yaramazsa lodash kullanıyorum ve bunun hızlı bir şekilde çalışmasını sağlayabilecek diğer kütüphanelere açık.

EDIT bu, arka uçtadır ve nadiren çalışır, bu nedenle boyut, hız vb. Için en iyi duruma getirmek için gerekli değildir. Aslında kod okunabilirliği, gelecekteki devreler için bir artı olabilir.

EDIT 2 Bu, başvurulan çoğaltmayla aynı DEĞİLDİR. Yani, aynı nesne için bu atamayı birden çok kez yapabilmem gerekiyor ve "çift" yanıt her seferinde alt anahtarların üzerine yazılacak. Lütfen tekrar açılsın! Size almak için

+5

1. '' 'ile ayırın. 3. ??????? 4. PROFIT !!!! 111 – zerkms

+0

Ha evet hepsi bu konuyla ilgili '' ?????? '' bölüm – tyler

+0

Açısalların ['$ parse'] (https://docs.angularjs.org/api/ng/service/ $ parse) bunu gayet iyi yapıyor. Belki de [kaynak kodu] 'na bir bakın (https://github.com/angular/angular.js/blob/master/src/ng/parse.js#L956) bunun için – Phil

cevap

7

Sen Söz konusu lodash söz, bu yüzden ben onların kolay nesne set() ve get() fonksiyonlarını eklemek gerekir düşündüm. Burada bu konuda daha fazla bilgi bulabilirsiniz

_.set(record, 'availability_meta.supplier.price', 99); 

: https://lodash.com/docs#set

Bu işlevler vb, dizi dizinleri belirtmek gibi sen de daha karmaşık şeyler yapalım :) Bu konuda

+1

yup, burada en iyi cevap bu IMHO .. Bunu kullandım .. –

+1

Anlaştık. Böyle bir şeyin nasıl uygulanacağını anlamanız, veri yapılarında iyi bir egzersiz olabilir, bunu uygulamak zorunda kalmazsınız ve bunu kendiniz sürdürmek zorunda kalmazsınız. OP açık bir şekilde zaten lodash kullandığından bahseder, bu kabul edilen cevap olması gerektiği gibi görünüyor. – codermonkeyfuel

8

şey başlatan:

function assignProperty(obj, path, value) { 
    var props = path.split(".") 
     , i = 0 
     , prop; 

    for(; i < props.length - 1; i++) { 
     prop = props[i]; 
     obj = obj[prop]; 
    } 

    obj[props[i]] = value; 

} 

varsayarsak:

var arr = ["foo.bar.baz", 1]; 

kullanarak derdim:

assignProperty(record, arr[0], arr[1]); 

Örnek: http://jsfiddle.net/x49g5w8L/

+0

assignProperty öğesini çağırdığınızda param eksiksiniz. – ianaya89

+1

@ ianaya89: Teşekkürler, düzeltildi. –

+0

@PastorBones: Düzenlemenizi geri aldım. Yazılma şekli tasarlandığı gibidir. Bu süptildir, fakat '1' uzunluğuna gitmesinin nedeni, döngü bittikten sonra, '' son özelliğe eşittir (örnekte 'baz'). Böylece işlevdeki son satır, değeri doğru özelliğe atar. –

2

Sadece

record['foo.bar.baz'] = 99; 

yapmak Ama bu nasıl iş ki? Bu kesinlikle Object.observe kullanarak, V8 ortamı (Chrome veya Düğüm uyumu) ​​ile maceracı için. Nesneyi gözlemliyoruz ve yeni mülkler ekliyoruz. "Özellik" foo.bar.baz eklendiğinde (bir ödevle), bunun noktalı bir özellik olduğunu algılar ve bir öbeğe record['foo']['bar.baz'] (varsa record['foo'] oluşturarak) atarız; record['foo']['bar']['baz']. Böyle giderse:
function enable_dot_assignments(changes) { 

    // Iterate over changes 
    changes.forEach(function(change) { 

     // Deconstruct change record. 
     var object = change.object; 
     var type = change.type; 
     var name = change.name; 

     // Handle only 'add' type changes 
     if (type !== 'add') return; 

     // Break the property into segments, and get first one. 
     var segments = name.split('.'); 
     var first_segment = segments.shift(); 

     // Skip non-dotted property. 
     if (!segments.length) return; 

     // If the property doesn't exist, create it as object. 
     if (!(first_segment in object)) object[first_segment] = {}; 

     var subobject = object[first_segment]; 

     // Ensure subobject also enables dot assignments. 
     Object.observe(subobject, enable_dot_assignments); 

     // Set value on subobject using remainder of dot path. 
     subobject[segments.join('.')] = object[name]; 

     // Make subobject assignments synchronous. 
     Object.deliverChangeRecords(enable_dot_assignments); 

     // We don't need the 'a.b' property on the object. 
     delete object[name]; 
    }); 
} 

Şimdi sadece bu tür atamaları veya sizin için çalışmıyor olabilir asenkron, olacağı, ancak,
Object.observe(record, enable_dot_assignments); 
record['foo.bar.baz'] = 99; 

dikkat

yapabilirsiniz. Bunu çözmek için, atamadan hemen sonra Object.deliverChangeRecords numaralı telefonu arayın. Veya, hem sözdizimsel hoş olmasa da, ayrıca gözlemci kurma, bir yardımcı fonksiyon yazabiliriz: belki bu örnekteki gibi

function dot_assignment(object, path, value) { 
    Object.observe(object, enable_dot_assignments); 
    object[path] = value; 
    Object.deliverChangeRecords(enable_dot_assignments); 
} 

dot_assignment(record, 'foo.bar.baz', 99); 
1

şey. Sağlanan bir nesneyi genişletecek veya herhangi bir nesne sağlanmıyorsa bir tane oluşturacaktır.Nesnede zaten var olan anahtarlar sağlarsanız, doğada yıkıcıdır, ancak eğer istediğin şey değilse, bunu değiştirebilirsin. ECMA5 kullanır.

/*global console */ 
 
/*members split, pop, reduce, trim, forEach, log, stringify */ 
 
(function() { 
 
    'use strict'; 
 

 
    function isObject(arg) { 
 
     return arg && typeof arg === 'object'; 
 
    } 
 

 
    function convertExtend(arr, obj) { 
 
     if (!isObject(obj)) { 
 
      obj = {}; 
 
     } 
 

 
     var str = arr[0], 
 
      last = obj, 
 
      props, 
 
      valProp; 
 

 
     if (typeof str === 'string') { 
 
      props = str.split('.'); 
 
      valProp = props.pop(); 
 
      props.reduce(function (nest, prop) { 
 
       prop = prop.trim(); 
 
       last = nest[prop]; 
 
       if (!isObject(last)) { 
 
        nest[prop] = last = {}; 
 
       } 
 

 
       return last; 
 
      }, obj); 
 

 
      last[valProp] = arr[1]; 
 
     } 
 

 
     return obj; 
 
    } 
 

 
    var x = ['fum'], 
 
     y = [ 
 
      ['foo.bar.baz', 1], 
 
      ['foo.bar.fum', new Date()], 
 
      ['qux.qaz', 'abc'], 
 
      ['foshizzle', 200] 
 
     ], 
 
     z = ['qux.qux', null], 
 
     record = convertExtend(x); 
 

 
    y.forEach(function (yi) { 
 
     convertExtend(yi, record); 
 
    }); 
 

 
    convertExtend(z, record); 
 
    document.body.textContent = JSON.stringify(record, function (key, value, Undefined) { 
 
     /*jslint unparam:true */ 
 
     /*jshint unused:false */ 
 
     if (value === Undefined) { 
 
      value = String(value); 
 
     } 
 

 
     return value; 
 
    }); 
 
}());

1

ne Tıpkı bir şey yapmak ?

function convertDotPathToNestedObject(path, value) { 
    const [last, ...paths] = path.split('.').reverse(); 
    return paths.reduce((acc, el) => ({ [el]: acc }), { [last]: value }); 
} 

convertDotPathToNestedObject('foo.bar.x', 'FooBar') 
// { foo: { bar: { x: 'FooBar' } } } 
+0

GraphQL ile çalışıyorum ve bu çok iç içe güncellemelerle çalışmam gereken şeylere yakın. Bakın: https://medium.com/pro-react/a-brief-talk-about-immutability-and-react-s-helpers-70919ab8ae7c –

İlgili konular