问题描述
我正在尝试为单元测试编写一个快速的模拟功能。为了测试我的断言,我需要在页面中添加一个HTML元素,并且该元素包含字符串化的JSON。被测系统采用字符串化的JSON,对其进行修改,然后将其转换回并重新插入。
在DOM中创建模拟插入时,我发现一个奇怪的地方,当我访问字符串化的JSON时,好像只是一个字符串时实际上是JSON。
这是代码示例
var mockJson = JSON.stringify({
name: "Foo",data: {}
});
var mockScript = document.createElement("script");
mockScript.id = "myElement";
mockScript.textContent = mockJson;
document.body.appendChild(mockScript);
上面的代码实际上可以正常工作。运行时,我可以在DOM中看到附加的#myElement
,其中包含我的字符串化模拟对象。
但是它也会引发错误:
VM136:1未捕获的语法错误:意外的令牌':'
此错误似乎专门在脚本的最后一行上运行。我很困惑,因为:
不在那一行。但是我意识到这实际上是将字符串化的mockJson
当作JSON ...,但同时运行良好。
我测试了删除复杂的模拟对象并将其替换为简单的字符串:
var mockJson = "foo";
var mockScript = document.createElement("script");
mockScript.id = "myElement";
mockScript.textContent = mockJson;
document.body.appendChild(mockScript);
在运行该脚本时,它仍然可以完成预期的工作,我的脚本元素在DOM中显示,其中包含字符串“ foo”。但是在这种情况下也会出现一个错误:
VM179:1未捕获的ReferenceError:未定义foo
因此,尽管它被声明为字符串,它仍试图将foo
插入为变量。
为什么会这样?为什么既要同时按预期将其添加为字符串,又抛出此错误?
小提琴示例
var mockJson = JSON.stringify({
name: "Foo",data: {}
});
var mockScript = document.createElement("script");
mockScript.id = "myElement";
mockScript.textContent = mockJson;
document.body.appendChild(mockScript);
解决方法
这与将数据附加到DOM无关。这就是将JSON放入脚本元素时发生的情况。
脚本元素应包含 JavaScript ,而不是JSON。
字符串文字是一个完全有效(尽管完全没有意义的)JavaScript表达式。
"A string"
对象文字不是。
{ "property": "value","second property": "value" }
这是因为语法{}
用于对象文字和块。在这种情况下,它被视为块。第一个属性是标签。它后面的字符串是无意义的字符串(如上例所示)。然后下一个:
触发错误。
如果要将JSON添加到页面以进行自动测试,请在有意义的地方使用一个元素。例如,使用<pre>
元素而不是<script>
元素。
一个有点肮脏的技巧是在script元素上设置type
属性,以声明它不是JavaScript。