How to store a javascript function in JSON

I have a JS object I would like to save in Local Storage for future use, and I cannot parse it to a string.

Code:

JSON.stringify({
    a: 5,
    b: function (param) {
        return param;
    }
})

Result:

"{"a":5}"

How do I save it for future use, if not with JSON?

(And creating my own Lexer-Parser to interupt string function I dont think is an option)

7

I’d recommend this approach:

Store arguments and the body in your json:

{"function":{"arguments":"a,b,c","body":"return a*b+c;"}}

Now parse json and instantiate the function:

var f = new Function(function.arguments, function.body);

I think it’s save

4

Usually a question like this indicates an X/Y problem: You need to do X, you think Y will help you do that, so you try to do Y, can’t, and ask how to do Y. It would frequently be more useful to ask how to do X instead.

But answering the question asked: You could use replacer and reviver functions to convert the function to a string (during stringify) and back into a function (during parse) to store a string version of the function, but there are all sorts of issues with doing that, not least that the scope in which the function is defined may well matter to the function. (It doesn’t matter to the function you’ve shown in the question, but I assume that’s not really representative.) And converting a string from local storage into code you may run means that you are trusting that the local storage content hasn’t been corrupted in a malicious way. Granted it’s not likely unless the page is already vulnerable to XSS attacks, but it’s an issue to keep in mind.

Here’s an example, but I don’t recommend it unless other options have been exhausted, not least because it uses eval, which (like its close cousin new Function)) can be a vector for malicious code:

// The object
var obj = {
    a: 5,
    b: function (param) {
        return param;
    }
};

// Convert to JSON using a replacer function to output
// the string version of a function with /Function(
// in front and )/ at the end.
var json = JSON.stringify(obj, function(key, value) {
  if (typeof value === "function") {
    return "/Function(" + value.toString() + ")/";
  }
  return value;
});

// Convert to an object using a reviver function that
// recognizes the /Function(...)/ value and converts it
// into a function via -shudder- `eval`.
var obj2 = JSON.parse(json, function(key, value) {
  if (typeof value === "string" &&
      value.startsWith("/Function(") &&
      value.endsWith(")/")) {
    value = value.substring(10, value.length - 2);
    return (0, eval)("(" + value + ")");
  }
  return value;
});
document.body.innerHTML = obj2.b(42);

The construct (0, eval)("(" + value + ")"); ensures that eval runs at global scope rather than within the scope of the reviver function. Normally eval has a magic ability to use the scope you call it in, but that only works when you call it directly. Indirect eval as shown (or just var e = eval; e("(" + value + ")");) doesn’t have that magic ability, it runs at global scope.

7

You can’t store functions in JSON.

The value in JSON may contain only string, number, object, array, true, false or null:

Check out it on JSON site.

6

One simple way of doing this is

var dstr = JSON.stringify( { a: 5
                           , b: x => x
                           }
                         , (k,v) => typeof v === "function" ? "" + v : v
                         );

2

I’ve taken to storing the function name, along with the parameter values, in an array, with the first item in the array being the function name prepended with a $, to separate them from normal arrays.

{
    "object": {
        "your-function": ["$functionName", "param-1", "param-2"],
        "color": ["$getColor", "brand", "brand-2"],
        "normal-array": ["normal", "array"]
        ...
    }
}

In the above example I have Sass and JS functions to retrieve color values from a global map/object. Parsing the function in this manner naturally requires custom code, but in terms of “storing” functions in JSON, I like this way of doing it.

3

I have created JSON.parseIt() and JSON.stringifyIt() functions based on the first answer without using eval

JSON.stringifyIt = (obj)=>{
    return(
        JSON.stringify(obj, function(key, value) {
            if (typeof value === "function") {
                return "/Function(" + value.toString() + ")/";
            }
            if(typeof value === "string"){
                return "/String(" + value.toString() + ")/"
            }
            return value;
        })
    )
}
JSON.parseIt=(json)=>{
    return(
        JSON.parse(json, function(key, value) {
            if (typeof value === "string" &&
            value.startsWith("/Function(") &&
            value.endsWith(")/")) {
                value = value.substring(10, value.length - 2);
                var string = value.slice(value.indexOf("(") + 1, value.indexOf(")"));
                if(/S+/g.test(string)){
                    return (new Function(string,value.slice(value.indexOf("{") + 1, value.lastIndexOf("}"))))

                }else{
                    return (new Function(value.slice(value.indexOf("{") + 1, value.lastIndexOf("}"))));
                }
                
            }
            if (typeof value === "string" &&
            value.startsWith("/String(") &&
            value.endsWith(")/")){
                value = value.substring(8, value.length - 2);
            }
            return value;
        })
    )
}

// DEMO

var obj = {
    string:"a string",
    number:10,
    func:()=>{
        console.log("this is a string from a parsed json function");
    },
    secFunc:(none,ntwo)=>{console.log(none + ntwo)} ,
    confuse:"/Function(hello)/"
}
const stringifiedObj = JSON.stringifyIt(obj);
console.log("the stringified object is: ",stringifiedObj);

const parsedObj = JSON.parseIt(stringifiedObj);

// console.log("the parsed object is:  ",parsedObj);
console.log(parsedObj.string);
console.log(parsedObj.number);
console.log(parsedObj.confuse);
parsedObj.func();
parsedObj.secFunc(5,6);

The problems I fixed were

  • Removed eval.
  • there was a problem in the stringifying and parsing that if I give a string like
    “/Function(hello)/” will be a function when parsed
  • Made it to two functions
  • Added parameter insertation

1

For someone that still need include, for whatever reason, the function definition in JSON, this code can help (but can be slow depending object size):

function Object2JsonWithFunctions(o, space = null) {
var functionList = {}
var fnSeq = 0;

var snrepl = function(k,v){
    if(typeof v === 'function'){
        fnSeq++;
        var funcName = `___fun${fnSeq}___`;
        var funcText = ''+v;
        
        functionList[funcName] = funcText
        
        return funcName;
    }
    
    return v;
}

var RawJson = JSON.stringify(o, snrepl, space);

for(func in functionList){
    var PropValue = `"${func}"`;
    RawJson = RawJson.replace(PropValue, functionList[func])
}

return RawJson;}

The code will do the normal convert to JSON.
For functions, the original stringify will return as “prop”:”function()…” (function as a string)… The code above will create a placeholder (e.g: “prop”:”fn1“) and create a function list… After, will replace every placeholder to original function body…

If you know the keys that can be functions then this will work

const functionKeys = [ '$alpha', '$omega' ]


const str = JSON.stringify({
  heart: 'soul',
  $alpha ({ one }) {
    console.log(one)
  },
  $omega: function ({ one, two }) {
    console.log(one, two)
  },
  nested: {
    $alpha: function $alpha({ one }) {
      console.log(one)
    },
    $omega: ({ one, two }) => {
      console.log(one, two)
    },
  }
}, onStringify)


const parsed = JSON.parse(str, onParse)

console.log('parsed', parsed)
parsed.$alpha({ one: 'faith' })
parsed.$omega({ one: 'light', two: 'and love' })
parsed.nested.$alpha({ one: 'helios and vesta' })
parsed.nested.$omega({ one: 'knowledge', two: 'is power' })


function onStringify (_, value) {
  return (typeof value === 'function') ? value.toString() : value
}


function onParse (key, value) {
  let formatted = value

  if (functionKeys.includes(key)) {
    const paramsStart = value.indexOf('(') + 1
    const paramsEnd = value.indexOf(')')

    const bodyStart = value.indexOf('{', paramsEnd) + 1
    const bodyEnd = value.lastIndexOf('}')

    formatted = Function(value.substring(paramsStart, paramsEnd), value.substring(bodyStart, bodyEnd))
  }

  return formatted
}

Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa Dịch vụ tổ chức sự kiện 5 sao Thông tin về chúng tôi Dịch vụ sinh nhật bé trai Dịch vụ sinh nhật bé gái Sự kiện trọn gói Các tiết mục giải trí Dịch vụ bổ trợ Tiệc cưới sang trọng Dịch vụ khai trương Tư vấn tổ chức sự kiện Hình ảnh sự kiện Cập nhật tin tức Liên hệ ngay Thuê chú hề chuyên nghiệp Tiệc tất niên cho công ty Trang trí tiệc cuối năm Tiệc tất niên độc đáo Sinh nhật bé Hải Đăng Sinh nhật đáng yêu bé Khánh Vân Sinh nhật sang trọng Bích Ngân Tiệc sinh nhật bé Thanh Trang Dịch vụ ông già Noel Xiếc thú vui nhộn Biểu diễn xiếc quay đĩa Dịch vụ tổ chức tiệc uy tín Khám phá dịch vụ của chúng tôi Tiệc sinh nhật cho bé trai Trang trí tiệc cho bé gái Gói sự kiện chuyên nghiệp Chương trình giải trí hấp dẫn Dịch vụ hỗ trợ sự kiện Trang trí tiệc cưới đẹp Khởi đầu thành công với khai trương Chuyên gia tư vấn sự kiện Xem ảnh các sự kiện đẹp Tin mới về sự kiện Kết nối với đội ngũ chuyên gia Chú hề vui nhộn cho tiệc sinh nhật Ý tưởng tiệc cuối năm Tất niên độc đáo Trang trí tiệc hiện đại Tổ chức sinh nhật cho Hải Đăng Sinh nhật độc quyền Khánh Vân Phong cách tiệc Bích Ngân Trang trí tiệc bé Thanh Trang Thuê dịch vụ ông già Noel chuyên nghiệp Xem xiếc khỉ đặc sắc Xiếc quay đĩa thú vị
Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa
Thiết kế website Thiết kế website Thiết kế website Cách kháng tài khoản quảng cáo Mua bán Fanpage Facebook Dịch vụ SEO Tổ chức sinh nhật