简体   繁体   中英

Appending a string to the DOM converts to JSON

I am trying to write a quick mock function for a unit test. In order to test my assertions, I need a HTML element to be in the page, and this element contains stringified JSON. The system under test takes the stringified JSON, modifies it, converts it back and re-inserts it.

When creating my mock insertion into the DOM I notice an oddity where my stringified JSON seems to be accessed as though it were actually JSON when it's just a string.

Here's an example of the code

var mockJson = JSON.stringify({
    name: "Foo",
    data: {}
});
var mockScript = document.createElement("script");
mockScript.id = "myElement";
mockScript.textContent = mockJson;
document.body.appendChild(mockScript);

This code above actually works fine. When run, I can see the appended #myElement in the DOM and it contains my stringified mock object.

However it also throws an error:

VM136:1 Uncaught SyntaxError: Unexpected token ':'

This error appears to run specifically on the last line of the script. I was confused because : isn't in that line. But I realised it's actually treating the stringified mockJson as JSON... but also running fine at the same time.

I tested removing the complex mock object and replacing it with a simple string:

var mockJson = "foo";
var mockScript = document.createElement("script");
mockScript.id = "myElement";
mockScript.textContent = mockJson;
document.body.appendChild(mockScript);

When running this script it still also does what it's supposed to, my script element shows in the DOM with the string "foo" inside it. But an error also appears that in this case says:

VM179:1 Uncaught ReferenceError: foo is not defined

So it's trying to insert foo as a variable, despite it being declared as a string.

Why is this happening? Why is it both simultaneously adding it as a string as intended, but also throwing this error?

Fiddle example

 var mockJson = JSON.stringify({ name: "Foo", data: {} }); var mockScript = document.createElement("script"); mockScript.id = "myElement"; mockScript.textContent = mockJson; document.body.appendChild(mockScript);

This has nothing to do with appending data to the DOM. It is just what happens when you put JSON in a script element.

Script elements are expected to contain JavaScript , not JSON.

A string literal is a perfectly valid (albeit entirely pointless) JavaScript expression.

 "A string"

An object literal is not.

 { "property": "value", "second property": "value" }

This is because the syntax {} is used for both object literals and blocks. In this context it is treated as a block . The first property is a label. The string after it a pointless string (as in the previous example). Then the next : triggers the error.

If you want to add JSON to the page for an automated test, use an element where it it makes some sense. For example a <pre> element instead of a <script> element.

A somewhat dirty hack would be to set a type attribute on the script element to declare that it isn't JavaScript.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM