eval

2011-02-13 33 views
13

का उपयोग किये बिना स्ट्रिंग नाम से नेमस्पेस्ड जावास्क्रिप्ट ऑब्जेक्ट एक्सेस करें मैं एक ऐसी स्थिति में भाग गया जहां मुझे सर्वर से जावास्क्रिप्ट ऑब्जेक्ट तक पहुंच की आवश्यकता है। सर्वर फ़ंक्शन या ऑब्जेक्ट का स्ट्रिंग नाम देता है और अन्य मेटाडेटा के आधार पर मैं ऑब्जेक्ट का मूल्यांकन अलग-अलग करता हूं।eval

मूल रूप से मैं मूल्यांकन कर रहा था (eval([string])) और सबकुछ ठीक था। हाल ही में मैं दिमाग की सुरक्षा शांति के लिए eval का उपयोग न करने के लिए फ़ंक्शन को अपडेट कर रहा था, और मैं नामांकित वस्तुओं/कार्यों के साथ एक समस्या में भाग गया।

विशेष रूप से मैंने eval([name]) को window[name] के साथ वैश्विक ऑब्जेक्ट बनाम eval से वर्ग ब्रैकेट वाक्यविन्यास के माध्यम से ऑब्जेक्ट तक पहुंचने का प्रयास करने की कोशिश की।

लेकिन मैं उदाहरण के लिए, namespaced वस्तुओं के साथ कोई समस्या हुई थी:

var strObjName = 'namespace.serviceArea.function'; 
// if I do 
var obj = eval(strObjName); // works 

// but if I do 
var obj = window[strObjName]; // doesn't work 

किसी को भी एक अच्छा समाधान namespaced तार के साथ eval के उपयोग से बचने के लिए साथ आने कर सकते हैं?

उत्तर

22

आप . पर विभाजित कर सकते हैं और बदले में प्रत्येक संपत्ति को हल कर सकते हैं। यह ठीक हो जाएगा तो लंबी श्रृंखला में संपत्ति के नाम से कोई भी एक . वर्ण के रूप में:

var strObjName = 'namespace.serviceArea.function'; 
var parts = strObjName.split("."); 
for (var i = 0, len = parts.length, obj = window; i < len; ++i) { 
    obj = obj[parts[i]]; 
} 
alert(obj); 
+0

@ टिम यही मैं सोच रहा था, लेकिन आप इसे मेरे सामने मिला! :) –

+0

¬¬ आपको पहले मिला? :(हाहा +1 – JCOC611

+0

@ टिमडाउन का उल्लेख है कि इस तरह के नाम-रिक्त स्थान का उपयोग वास्तव में मूल रूप से समर्थित नहीं है और कोड को काफी गन्दा और बनाए रखने में कठोर हो सकता है। ऐसा लगता है कि किसी अन्य भाषा से शैलियों को पोर्टल करने पर ऐसा लगता है कि वहां बेहतर विकल्प – Raynos

2

मैं इस के साथ आया था:

function reval(str){ 
    var str=str.split("."),obj=window; 
    for(var z=0;z<str.length;z++){ 
    obj=obj[str[z]]; 
    } 
    return obj; 
} 
eval("window.this.that"); 
reval("this.that"); //would return the object 
reval("this.that")(); //Would execute 
-1

निम्नलिखित है कि मानता strObjName के कुछ हिस्सों अलग होती है . द्वारा और जब तक यह कार्य करने के लिए नीचे हो जाता है खिड़की पर शुरू के माध्यम से लूप आप चाहते हैं:

var strObjParts = strObjName.split('.'); 
var obj = window; 
for(var i in strObjParts) { 
    obj = obj[strObjParts[i]]; 
} 
+1

'इन ... के लिए सामान्य उदाहरण में इस उदाहरण के लिए नहीं होगा जहां आदेश आवश्यक है, क्योंकि 'इन ... इन' के गणना आदेश की गारंटी नहीं है। लूप के लिए सामान्य 'सामान्य' का प्रयोग करें। –

+0

जावास्क्रिप्ट में सरणी पर लूप के लिए इन-इन का उपयोग न करें। यह बुरा है। – hugomg

+0

@Tim: धन्यवाद। मुझे एहसास नहीं हुआ कि आदेश की गारंटी नहीं थी। @missingno: मुझे यकीन नहीं है कि आप बुराई से क्या मतलब है। –

1

मैं जानता हूँ कि इस satisfact उत्तर दिया गया है पूछताछ करने के लिए ओरी, लेकिन मुझे हाल ही में यह मुद्दा था, लेकिन मूल्य के लिए लिखने के साथ। मैं स्ट्रिंग पथ के आधार पर पढ़ने और लिखने को संभालने के लिए अपनी स्थिर कक्षा के साथ आया था। डिफ़ॉल्ट पथ विभाजक . है लेकिन आप इसे कुछ भी होने के लिए संशोधित कर सकते हैं, जैसे कि /। इस कोड पर भी टिप्पणी की गई है कि आपको आश्चर्य है कि यह कैसे काम करता है।

(function(){ 
    var o = {}, c = window.Configure = {}, seperator = '.'; 

    c.write = function(p, d) 
    { 
     // Split the path to an array and assaign the object 
     // to a local variable 
     var ps = p.split(seperator), co = o; 

     // Iterate over the paths, skipping the last one 
     for(var i = 0; i < ps.length - 1; i++) 
     { 
      // Grab the next path's value, creating an empty 
      // object if it does not exist 
      co = (co[ps[i]])? co[ps[i]] : co[ps[i]] = {}; 
     } 

     // Assign the value to the object's last path 
     co[ps[ps.length - 1]] = d; 
    } 

    c.read = function(p) 
    { 
     var ps = p.split(seperator), co = o; 
     for(var i = 0; i < ps.length; i++) 
     { 
      co = (co[ps[i]])? co[ps[i]] : co[ps[i]] = {}; 
     } 
     return co; 
    } 
})(); 
2

मैंने रिकर्सन का उपयोग करके एक अलग समाधान लिखा है। मैं इनपुट तत्वों के नाम विशेषता नामस्थान के लिए इसका उपयोग कर रहा था। उदाहरण के लिए, उदाहरण के लिए,

<input type="number" name="testGroup.person.age" /> 

और मान लें कि हम उस इनपुट का मान "25" पर सेट करते हैं।

var data = { 
    testGroup: { 
     person: { 
      name: null, 
      age: null, 
      salary: null 
     } 
    } 
}; 

तो यहां लक्ष्य स्वचालित रूप से उस डेटा संरचना में सही स्थिति में हमारे इनपुट तत्व में मूल्य डालने के लिए है: हम भी कहीं न कहीं हमारे कोड में एक वस्तु है।

मैं इस छोटे से समारोह एक नेस्टेड के आधार पर वस्तु बनाने के लिए लिखा है नामस्थान की जो कुछ भी सरणी आप इसे पारित:

var buildObject = function (obj, namespaceArray, pos) { 
    var output = {}; 

    output[namespaceArray[pos]] = obj; 

    if (pos > 0) { 
     output = buildObject(output, namespaceArray, pos-1); 
    } 

    return output; 
}; 

यह कैसे काम करता है? यह namespaceArray सरणी के अंत में शुरू होता है, और एक संपत्ति के साथ एक वस्तु बनाता है, जिसका नाम namespaceArray में अंतिम स्लॉट में जो भी है, और जिसका मान obj है।फिर यह उस ऑब्जेक्ट को अतिरिक्त ऑब्जेक्ट्स में लपेटता है जब तक कि यह namespaceArray में नामों से बाहर नहीं हो जाता है। posnamespaceArray सरणी की लंबाई है। आप इसे पहले फंक्शन कॉल में काम कर सकते हैं, if (typeof(pos) === "undefined") pos = namespaceArray.length - 1 जैसे कुछ, लेकिन फिर आपके पास फ़ंक्शन रिकर्स किए जाने पर हर बार मूल्यांकन करने के लिए एक अतिरिक्त कथन होगा।

सबसे पहले, हम नाम स्थान विभाजक चारों ओर एक सरणी में input की name विशेषता विभाजित है और इनपुट के मूल्य मिलता है:

var namespaceArray = inputElement.name.split("."), 
    obj = inputElement.value; 

// Usually you'll want to do some undefined checks and whatnot as well 

तो हम बस हमारी फ़ंक्शन को कॉल करें और कुछ चर के परिणाम में निर्दिष्ट करें:

var myObj = buildObject(obj, namespaceArray, namespaceArray.length - 1); 

myObj अब इस तरह दिखेगा:

{ 
    testGroup: { 
     person: { 
      age: 25 
     } 
    } 
} 

इस बिंदु मैं jQuery के विस्तार समारोह का उपयोग करें कि संरचना मूल डेटा वस्तु में वापस मर्ज करने के लिए कम:

data = $.extend(true, data, myObj); 
हालांकि

, दो वस्तुओं विलय ढांचे से मुक्त जावास्क्रिप्ट में करने के लिए बहुत मुश्किल नहीं है और वहाँ existing code के बहुत है जो काम अच्छी तरह से हो जाता है।

मुझे यकीन है कि यह करने के लिए और अधिक कुशल तरीके हैं, लेकिन यह विधि मेरी आवश्यकताओं को अच्छी तरह से पूरा करती है।

0

pastebin पर मेरे नमूना: http://pastebin.com/13xUnuyV

मैं तुम्हें कोड पसंद आया, और मैं PHP का उपयोग समान सामान का एक बहुत कुछ किया। लेकिन यहां तक ​​कि कठिन था क्योंकि मैं ... तो मैंने जवाब @LordZardeck (https://stackoverflow.com/a/9338381/1181479) और @Alnitak (https://stackoverflow.com/a/6491621/1181479) का उपयोग किया।

और यहाँ मैं क्या है, बस इसे का उपयोग करें:

var someObject = { 
     'part1' : { 
      'name': 'Part 1', 
      'size': '20', 
      'qty' : '50' 
     }, 
     'part2' : { 
      'name': 'Part 2', 
      'size': '15', 
      'qty' : '60' 
     }, 
     'part3' : [ 
      { 
       'name': 'Part 3A РУКУ!!!', 
       'size': '10', 
       'qty' : '20' 
      }, { 
       'name': 'Part 3B', 
       'size': '5', 
       'qty' : '20' 
      }, { 
       'name': 'Part 3C', 
       'size': '7.5', 
       'qty' : '20' 
      } 
     ] 
    }; 

    //var o = {}, c = window.Configure = {}, seperator = '.'; 

    var c = function(){ 
     this.o = {}; 
     this.seperator = "."; 
     this.set = function(obj){ 
      this.o = obj; 
     } 
     this.write = function(p, d) { 
      p = p.replace(/\[(\w+)\]/g, '.$1'); // convert indexes to properties 
      p = p.replace(/^\./, ''); // strip leading dot 
      // Split the path to an array and assaign the object 
      // to a local variable 
      var ps = p.split(this.seperator), co = this.o; 

      // Iterate over the paths, skipping the last one 
      for(var i = 0; i < ps.length - 1; i++) 
      { 
       // Grab the next path's value, creating an empty 
       // object if it does not exist 
       co = (co[ps[i]])? co[ps[i]] : co[ps[i]] = {}; 
      } 

      // Assign the value to the object's last path 
      co[ps[ps.length - 1]] = d; 
     } 
     this.read = function(p) { 
      p = p.replace(/\[(\w+)\]/g, '.$1'); // convert indexes to properties 
      p = p.replace(/^\./, ''); // strip leading dot 
      var ps = p.split(this.seperator), co = this.o; 
      /* 
      for(var i = 0; i < ps.length; i++) 
      { 
       co = (co[ps[i]])? co[ps[i]] : co[ps[i]] = {}; 
      } 
      */ 
      while (ps.length) { 
       var n = ps.shift(); 
       if (n in co) { 
        co = co[n]; 
       } else { 
        return; 
       } 
      } 
      return co; 
     } 

    }; 

    var n = new c(); 
    n.set(someObject); 
    console.log('whas'); 
    console.log('n.read part.name', n.read('part1.name')); 
    n.write('part3[0].name', "custom var"); 
    console.log('part1.name now changed'); 
    n.write('part1.name', "tmp"); 
    console.log('n.read part.name', n.read('part1.name')); 
    console.log('----'); 
    console.log('before', someObject); 
    console.log('someObject.part1.name', someObject.part1.name); 
    console.log('someObject.part3[0].name', someObject.part3[0].name); 
6

बस सोचा था कि क्योंकि मैं दूसरे दिन यह बना मैं इस का हिस्सा चाहते हैं। मुझे यह भी पता नहीं था कि जेएस में कमी कम थी!

function getByNameSpace(namespace, obj) { 
    return namespace.split('.').reduce(function(a,b) { 
      if(typeof a == 'object') return a[b]; 
      else return obj[a][b]; 
    }); 
} 

आशा किसी को पाता है यह उपयोगी ..

+0

मुझे यह विचार पसंद है! मेरे उद्देश्यों के लिए थोड़ा सा अनुकूलित .. http://codepen.io/anon/pen/taExD/ –

0

यह रूप में

(function (s) {return s.split('.').reduce(function(p,n) { p[n] = p[n] || {}; return p[n];},window);})("some.cool.namespace"); 

यह फिर से उपयोग

के लिए एक वैश्विक समारोह को सौंपा जा सकता इस तरह कार्यात्मक प्रोग्रामिंग तकनीक का उपयोग यह करने के लिए संभव है
window.ns = (function (s) {return s.split('.').reduce(function(p,n) { p[n] = p[n] || {}; return p[n];},window);}) 

फिर हम निम्नलिखित

कर सकते हैं
ns("some.cool").namespace = 5; 

if (5 != ns("some.cool.namespace")) { throw "This error can never happen" } 
संबंधित मुद्दे