2010-08-13 46 views
10

我在javax.scripting地圖實現中看到一些奇怪的行爲。在javax.scripting JavaScript環境中導入地圖

在線示例顯示了JS的環境中添加到列表的example

ScriptEngineManager mgr = new ScriptEngineManager(); 
    ScriptEngine jsEngine = mgr.getEngineByName("JavaScript"); 
    List<String> namesList = new ArrayList<String>(); 
    namesList.add("Jill"); 
    namesList.add("Bob"); 
    namesList.add("Laureen"); 
    namesList.add("Ed"); 
    jsEngine.put("namesListKey", namesList); 
    System.out.println("Executing in script environment..."); 
    try 
    { 
    jsEngine.eval("var names = namesListKey.toArray();" + "for(x in names) {" + " println(names[x]);" + "}" 
    + "namesListKey.add(\"Dana\");"); 
    } catch (ScriptException ex) 
    { 
    ex.printStackTrace(); 
    } 
    System.out.println(namesList); 

但是,如果你試圖做一個地圖類似的東西,你看到奇怪的行爲。首先,如果你嘗試迭代地圖鍵,例如

HashMap<String, Object> m = new HashMap<String, Object>(); 
jsEngine.put("map", m); 

有沒有辦法來獲得地圖鍵 - 如果你試圖通過按鍵進行迭代,你的方法業者名稱

jsEngine.eval(" for (var k in m.keySet()){ println(k)};"); 

結果:

notifyAll 
removeAll 
containsAll 
contains 
empty 
equals 
... 

在JS上下文中,可以使用m.get(key)而不是m[key]來映射地圖中的值,如果該鍵不存在,則會引發錯誤。任何人都可以對這種行爲有所瞭解,或者它是否被破壞?謝謝。

+0

這很有趣。它可能會遍歷對象keySet(在Rhino中你可以循環方法),但我不確定。我將不得不嘗試 – TheLQ 2010-08-13 21:41:51

回答

12

for..in在JavaScript中與Java中的每個東西都不是一回事,即使它們看起來很相似。 for..in在JavaScript中迭代對象中的屬性名稱。該方法的名字暴露於犀牛作爲本地Java的HashMap對象的屬性,就像如果你有以下的JavaScript對象:

{ 
notifyAll:function(){}, 
removeAll:function(){}, 
containsAll:function(){}, 
contains:function(){}, 
empty:function(){}, 
equals:function(){} 
} 

我的建議是,你要麼HashMap的鍵集轉換爲數組,使用方法Set .toArray,或者您使用Set.iterator()獲取迭代器。下面是一個簡短的Rhino腳本顯示您可以如何使用指定者方法做到這一點:

x=new java.util.HashMap(); 
x.put("foo","bar"); 
x.put("bat","bif"); 
x.put("barf","boo"); 

var keyArray = x.keySet().toArray(); 
for(var i=0, l = keyArray.length; i < l; i++){ 
    var key = keyArray[i]; 
    var value = x.get(key); 
    print(value); 
} 

,輸出:

bif 
bar 
boo 

這裏是如何使用Set.iterator做同樣的事情:

x=new java.util.HashMap(); 
x.put("foo","bar"); 
x.put("bat","bif"); 
x.put("barf","boo"); 

var keyIter = x.keySet().iterator(); 
while(keyIter.hasNext()){ 
    var key = keyIter.next() 
    var value = x.get(key); 
    print(value); 
} 
+0

謝謝,徹底和有用。 – 2010-08-14 22:28:17

2

如果將java.util.Map轉換爲本地對象,則JavaScript將變得更加清晰:

final Map<String,String> javaMap = new HashMap<>(); 
javaMap.put("alpha", "bravo"); 
javaMap.put("charlie", "delta"); 

final NativeObject jsMap = new NativeObject(); 
for (Map.Entry<String,String> entry : javaMap.entrySet()) { 
    jsMap.defineProperty(
     entry.getKey(), entry.getValue(), NativeObject.READONLY 
    ); 
} 

final ScriptEngine jsEngine = 
(new ScriptEngineManager()).getEngineByName("JavaScript"); 
jsEngine.put("map", jsMap); 
jsEngine.eval(
    "for (var idx in map) print(idx + '; ' + map[idx] + '\\n');" 
); 

否則,你被困在標準的Java語法中。

+0

不幸的是,您的NativeObject必須是Rhino或Nashorn API。它不存在於javax.script公共API中。 – jfrantzius 2015-07-10 15:32:10