diff --git a/javascript-extras.cabal b/javascript-extras.cabal
--- a/javascript-extras.cabal
+++ b/javascript-extras.cabal
@@ -1,5 +1,5 @@
 name:                javascript-extras
-version:             0.3.0.0
+version:             0.3.1.0
 synopsis:            Extra javascript functions when using GHCJS
 description:         Extra javascript functions when using GHCJS
 homepage:            https://github.com/louispan/javascript-extras#readme
@@ -21,6 +21,7 @@
                        JavaScript.Extras.Number
                        JavaScript.Extras.Property
                        JavaScript.Extras.JSVar
+                       JavaScript.Extras.JSVar.Unsafe
   build-depends:       base >= 4.7 && < 5
                      , deepseq >= 1.4 && < 2
                      , parallel >= 3.2 && < 4
@@ -31,6 +32,21 @@
     build-depends: ghcjs-base
   if !impl(ghcjs)
     build-depends: ghcjs-base-stub >= 0.1.0.1 && < 1
+
+executable javascript-extras-test
+  hs-source-dirs:      test/haskell
+  main-is:             Main.hs
+  ghc-options:         -Wall -threaded -rtsopts -with-rtsopts=-N
+  cpp-options:         -DGHCJS_BROWSER
+  build-depends:       base >= 4.7 && < 5
+                     , javascript-extras >= 0.3.1
+  default-language:    Haskell2010
+  default-extensions:  ApplicativeDo
+  if impl(ghcjs)
+    build-depends: ghcjs-base
+                 , ghcjs-prim >= 0.1 && < 0.2
+  if !impl(ghcjs)
+    build-depends: ghcjs-base-stub >= 0.1.0.2 && < 1
 
 source-repository head
   type:     git
diff --git a/jsbits/extras.js b/jsbits/extras.js
--- a/jsbits/extras.js
+++ b/jsbits/extras.js
@@ -1,3 +1,11 @@
+// Node module dependencies
+// Example package.json:
+// {
+//   "dependencies": {
+//     "javascript-stringify": "^1.6.0"
+//   }
+// }
+
 #include <ghcjs/rts.h>
 
 // zip list of string and JSVal to object, lists must have been completely forced first
@@ -10,4 +18,18 @@
         xs = CONS_TAIL(xs);
     }
     return obj;
+}
+
+var hge$javascriptStringify_ = null;
+function hje$stringify(v) {
+    if (!hge$javascriptStringify_) {
+        hge$javascriptStringify_ = require('javascript-stringify');
+    }
+    return hge$javascriptStringify_(v, null, null, { references: true })
+}
+
+// Injection attack! Use with care
+function hje$unstringify(str) {
+    eval("var ret=" + str);
+    return ret;
 }
diff --git a/src/JavaScript/Extras/JSVar.hs b/src/JavaScript/Extras/JSVar.hs
--- a/src/JavaScript/Extras/JSVar.hs
+++ b/src/JavaScript/Extras/JSVar.hs
@@ -1,3 +1,5 @@
+{-# LANGUAGE CPP #-}
+
 module JavaScript.Extras.JSVar where
 
 import Control.DeepSeq
@@ -12,6 +14,9 @@
 -- This is helpful when using OverloadedStrings
 newtype JSVar = JSVar J.JSVal
 
+instance Show JSVar where
+    show = JS.unpack . js_stringify
+
 instance J.IsJSVal JSVar
 
 instance J.PToJSVal JSVar where
@@ -33,3 +38,16 @@
 
 fromJS' :: JE.FromJS a => JSVar -> Maybe a
 fromJS' (JSVar v) = fromJS v
+
+#ifdef __GHCJS__
+
+foreign import javascript unsafe
+  "$r = hje$stringify($1);"
+  js_stringify :: JSVar -> J.JSString
+
+#else
+
+js_stringify :: JSVar -> J.JSString
+js_stringify _ = JS.empty
+
+#endif
diff --git a/src/JavaScript/Extras/JSVar/Unsafe.hs b/src/JavaScript/Extras/JSVar/Unsafe.hs
new file mode 100644
--- /dev/null
+++ b/src/JavaScript/Extras/JSVar/Unsafe.hs
@@ -0,0 +1,26 @@
+{-# OPTIONS_GHC -fno-warn-orphans #-}
+{-# LANGUAGE CPP #-}
+
+module JavaScript.Extras.JSVar.Unsafe where
+
+import Data.JSString as JS
+import qualified GHCJS.Types as J
+import JavaScript.Extras.JSVar as JE
+
+-- | Injection attack! Use with care
+instance Read JE.JSVar where
+    readsPrec _ str = [(js_eval (JS.pack str), [])]
+
+#ifdef __GHCJS__
+
+-- | Injection attack! Use with care
+foreign import javascript unsafe
+  "$r = hje$unstringify($1);"
+  js_eval :: J.JSString -> JSVar
+
+#else
+
+js_eval :: J.JSString -> JSVar
+js_eval _ = JSVar J.nullRef
+
+#endif
diff --git a/test/haskell/Main.hs b/test/haskell/Main.hs
new file mode 100644
--- /dev/null
+++ b/test/haskell/Main.hs
@@ -0,0 +1,47 @@
+{-# LANGUAGE CPP #-}
+{-# LANGUAGE OverloadedStrings #-}
+
+module Main (main) where
+
+import qualified Data.JSString as JS
+import qualified GHCJS.Foreign.Callback as J
+import qualified GHCJS.Types as J
+import qualified JavaScript.Extras as JE
+import qualified JavaScript.Extras.JSVar.Unsafe as JE
+
+#ifdef __GHCJS__
+
+test :: JE.JSVar -> IO ()
+test x = do
+    let str = show x
+        x' = read str :: JE.JSVar
+        str' = show x'
+    js_write $ "Test: " `mappend` (JS.pack str) `mappend` " == " `mappend` (JS.pack str')
+
+main :: IO ()
+main = do
+    test js_int
+    test js_obj
+    cb <- J.syncCallback' (pure (JE.toJS js_int))
+    test (JE.JSVar (J.jsval cb))
+    J.releaseCallback cb
+    test (JE.JSVar (J.jsval cb))
+
+foreign import javascript unsafe
+  "document.write('<p>' + $1 + '</p>')"
+  js_write :: JS.JSString -> IO ()
+
+foreign import javascript unsafe
+  "5"
+  js_int :: JE.JSVar
+
+foreign import javascript unsafe
+  "{ 'hello': 'world' }"
+  js_obj :: JE.JSVar
+
+#else
+
+main :: IO ()
+main = pure ()
+
+#endif
