2010-11-27 47 views
3

假設你有以下幾點:序列化和反序列化功能和JSON

function myfunc() { 
    // JS code 
} 

var args = '{ "strfield": "hello world", "numfield": 10, "funcfield": myfunc }'; 

的問題:你怎麼讓myfunc被替換的結果提交給了JSON解析器之前處理args變量myfunc.toString()(即函數的主體)?建議的解決方案應該可以處理任意函數和類似的JSON字符串。

+0

有趣...但我無法想象有一種方法可以實際獲取函數體中的代碼作爲字符串。但我可能是錯的,如果有辦法,那就太棒了:) – 2010-11-27 20:36:55

+0

咦?有這樣一種方式:myfunc.toString()調用沒有出現:P https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function/toString問題是沒有得到函數的代碼,而是優雅地用它代替字段的值,而不必破壞JSON解析器。 – dpq 2010-11-27 20:45:28

回答

-1

是否這樣?我不得不改變它,因爲你擁有的不是有效的JSON字符串,因爲myfunc沒有雙引號。所以我加了這些。

這解析它,得到的funcfield值,發現功能(儘管它假定它是在全球範圍內),電話toString()更新的funcfield,再stringifies它作爲JSON的價值。

例子:http://jsfiddle.net/patrick_dw/QUR6Z/

var myfunc = function() { 
    alert('hi'); 
}; 

var args = '{ "strfield": "hello world", "numfield": 10, "funcfield": "myfunc" }'; 
var parsed = JSON.parse(args); 

parsed.funcfield = window[parsed.funcfield].toString(); 
var stringified = JSON.stringify(parsed); 

alert(stringified); 

了這你是什麼意思?


編輯:

我想你可以使用目前的情況下,只要這方面包含擁有該功能的範圍內。

parsed.funcfield = this[parsed.funcfield].toString(); 

或者,如果你不能雙引號的功能名稱,你可以,如果你是某個數據是安全的使用,而不是eval

實施例:http://jsfiddle.net/patrick_dw/QUR6Z/1/

var args = '{ "strfield": "hello world", "numfield": 10, "funcfield": myfunc }'; 
window.eval('var parsed = ' + args); 

parsed.funcfield = parsed.funcfield.toString(); 
var stringified = JSON.stringify(parsed); 

alert(stringified); 
3

我們使用可選的第二replacer參數JSON.stringify來預處理鍵/值,在字符串化形式發射功能:

function stringify_with_fns(obj) { 
    return JSON.stringify(obj, function(key, value) { 
     return typeof value === "function" ? value.toString() : value; 
    }); 
} 

然後打開字符串化功能回到實際功能的出路,我們使用可選的第二個reviver參數JSON.parse,如

function parse_with_fns(json) { 
    return JSON.parse(json, function(key, value) { 
     if (looks_like_a_function_string(value)) { 
      return make_function_from_string(value); 
     } else { 
      return value; 
     } 
    }); 
} 

looks_like_a_function_string僅僅是一個正則表達式,並在make_function_from_string可先切開,使用eval

function looks_like_a_function_string(value) { 
    return /^function.*?\(.*?\)\s*\{.*\}$/.test(value); 
} 
function make_function_from_string(value) { 
    return eval(value); 
} 

爲了避免eval,我們可以挑選除了功能串找到它的參數和身體,所以我們可以將它們傳遞給new Function

function make_function_from_string(value) { 
    var args = value 
     .replace(/\/\/.*$|\/\*[\s\S]*?\*\//mg, '') //strip comments 
     .match(/\(.*?\)/m)[0]      //find argument list 
     .replace(/^\(|\)$/, '')     //remove parens 
     .match(/[^\s(),]+/g) || [],    //find arguments 
     body = value.match(/\{(.*)\}/)[1]   //extract body between curlies 

    return Function.apply(0, args.concat(body); 
} 

測試:

x = parse_with_fns(stringify_with_fns({a: function() {var x=1;}})) 
x.a 
> function anonymous() {var x=1;} 

但請注意,由於new Function創建的函數全部在全局範圍內,所以它們將失去其封閉範圍和閉包。

剩下的唯一問題是這是否有用。我想這可能是針對小型實用功能。

將概念擴展到序列化/反序列化正則表達式或日期對象作爲練習。