在Firefox和Chrome的控制台中,这有效(警报脚本内容):
var script = document.createElement("script");
script.textContent = (
function test() {
var a = 1;
}
);
document.getElementsByTagName("head")[0].appendChild(script);
alert(document.getElementsByTagName("head")[0].lastChild.textContent);
将此代码用作Firefox的Greasemonkey脚本也可以。
现在,如果要将“私有方法”do()
添加到test()
它不再适用,无论是Firefox / Chrome控制台还是Greasemonkey脚本:
var script = document.createElement("script");
script.textContent = (
function test() {
var a = 1;
var do = function () {
var b = 2;
};
}
);
document.getElementsByTagName("head")[0].appendChild(script);
alert(document.getElementsByTagName("head")[0].lastChild.textContent);
要在Greasemonkey脚本中完成此工作,我必须将所有代码放在CDATA
标记块中:
var script = document.createElement("script");
script.textContent = (<![CDATA[
function test() {
var a = 1;
var do = function() {
var b = 2;
};
}
]]>);
document.getElementsByTagName("head")[0].appendChild(script);
alert(document.getElementsByTagName("head")[0].lastChild.textContent);
这仅适用于Greasemonkey脚本;它会从Firefox / Chrome控制台引发错误。我不明白为什么我应该使用CDATA
标签,我没有XML规则要尊重,因为我没有使用XHTML。
要使其在Firefox控制台(或Firebug)中运行,我需要将CDATA
放入<>
和</>
等标记中:
var script = document.createElement("script");
script.textContent = (<><![CDATA[
function test() {
var a = 1;
var do = function() {
var b = 2;
};
}
]]></>);
document.getElementsByTagName("head")[0].appendChild(script);
alert(document.getElementsByTagName("head")[0].lastChild.textContent);
这不适用于Chrome控制台。我尝试在最后添加.toString()
,就像许多人一样(]]></>).toString();
),但它没用。
我尝试用标记名<>
</>
替换<foo>
和</foo>
,但这也不起作用。
如果我在另一个函数中定义var do = function(){}
,为什么我的第一个代码段不起作用?
即使我没有使用XHTML,为什么还要使用CDATA
作为解决方法?
如果没有使用Greasemonkey脚本,我为什么要为Firefox控制台添加<>
</>
?
最后,Chrome和其他浏览器的解决方案是什么?
修改
我的不好,我从未在JS中使用do-while而且我在一个简单的文本编辑器中创建了这个例子,所以我没有看到“do”是一个保留的关键字:p
但问题仍然存在,我没有在我的示例中初始化Javascript类。
使用这个新示例,Greasemonkey需要CDATA
,而E4X CDATA
<>
之间的Firefox需要</>
,Chrome就会失败:
var script = document.createElement("script");
script.textContent = (
<><![CDATA[var aClass = new AClass();
function AClass() {
var a = 1;
var aPrivateMethod = function() {
var b = 2;
alert(b);
};
this.aPublicMethod = function() {
var c = 3;
alert(c);
};
}
aClass.aPublicMethod();]]></>
);
document.getElementsByTagName("head")[0].appendChild(script);
问题:为什么?
答案 0 :(得分:4)
这里有多个错误/问题:
添加私有方法do()
无效,因为do
is a reserved word!
此代码在FF和Chrome(以及GM脚本)中均可正常运行:
var functionVar = (
function test() {
var a = 1;
var properlyNamedVariable = function() {
var b = 2;
};
}
);
console.log (functionVar.toString() );
如果您使用描述性变量名称,您将来不仅会为自己节省多少悲伤,而且几乎不会意外地使用保留字。
回复:"To make this work in a Greasemonkey script, I have to put all code in a CDATA tag"
。
Nope,该代码不工作。发生的事情是在Greasemonkey的沙箱中eval
'范围内发生了错误,但未报告Firefox的错误控制台。也就是说,它默默地失败了
如果您尝试从控制台执行test();
,则会收到错误:ReferenceError: test is not defined
。然而,如果您删除var do = function ...
代码并重新加载页面,则可以从控制台调用test()
。
同样,script.textContent = (<><![CDATA[ ...
代码也不起作用。它也默默地失败了,test()
没有被定义。与前一个示例相比,这种情况略有不同。
依赖于(<><![CDATA[ ...
技巧的代码在Chrome中不起作用,因为Chrome不支持在javascript中内联处理XML。这是Firefox which supports E4X的特权,而Chrome不是。
请format your code,这样做不是一件苦差事。
所以,在摘要中:
这是一种适用于Firefox,Chrome,其他几种浏览器以及Greasemonkey,Tampermonkey,Scriptish等的技术。它还有助于调试和测试,因为代码与内联变量声明分开:
正常定义您的函数或代码:
function testMyAdhocCode () {
"use strict";
var importInteger = 1;
var imA_PrivateFunction = function () {
var someOtherInteger = 2;
console.log (
"importInteger = ", importInteger,
" || someOtherInteger = ", someOtherInteger
);
};
console.log ("Greetings from testMyAdhocCode()!");
imA_PrivateFunction ();
}
然后将其注入页面(如果必须的话。最好不要注入代码,如果你能提供帮助的话。):
addJS_Node (testMyAdhocCode); //-- Function is just created.
// OR
addJS_Node (null, null, testMyAdhocCode); //-- Function is created and immediately run.
// OR
addJS_Node ("var someVar = 86;") //-- Adhoc code
// OR
addJS_Node ("preExistingFunction (42); ") //-- Run a preexisting function.
您的脚本中包含addJS_Node()
的位置为:
function addJS_Node (text, s_URL, funcToRun, runOnLoad) {
var D = document;
var scriptNode = D.createElement ('script');
if (runOnLoad) {
//--- Doesn't always fire on Chrome. Needs @run-at document-start.
scriptNode.addEventListener ("load", runOnLoad, false);
}
scriptNode.type = "text/javascript";
if (text) scriptNode.textContent = text;
if (s_URL) scriptNode.src = s_URL;
if (funcToRun) scriptNode.textContent = '(' + funcToRun.toString() + ')()';
var targ = D.getElementsByTagName ('head')[0] || D.body || D.documentElement;
targ.appendChild (scriptNode);
}
新问题更加相似。
addJS_Node()
等函数。如果你真的必须注入代码,那么正确的方法就是这样:
function main () {
"use strict"; // Keep this line!
var aClass = new aClass();
function aClass() {
var a = 1;
var aPrivateMethod = function() {
var b = 2;
alert(b);
};
this.aPublicMethod = function() {
var c = 3;
alert(c);
};
}
aClass.aPublicMethod();
//-- PUT ALL OF THE REST OF YOUR INJECTED CODE HERE.
}
addJS_Node (null, null, main);
将所有内容放在目标页面的 global 范围内是一个坏主意!但是,如果你坚持这样做,代码是这样的:
function aClass() {
"use strict"; // Keep this line!
var a = 1;
var aPrivateMethod = function() {
var b = 2;
alert(b);
};
this.aPublicMethod = function() {
var c = 3;
alert(c);
};
}
addJS_Node (aClass);
addJS_Node (
'var aClass = new aClass();'
+ 'aClass.aPublicMethod();'
);
答案 1 :(得分:1)
@BrockAdams Why is CDATA needed and not working everywhere the same way?的所有权利,想要在函数中编写所有内容并将内容插入脚本标记,谢谢。
感谢@polygenelubricants javascript get function body仅获取main()函数内容而不是函数及其内容。
var script = document.createElement("script");
function main()
{
var aClass = new AClass();
function AClass()
{
var a = 1;
var aPrivateMethod = function() {
var b = 2;
alert(b);
};
this.aPublicMethod = function() {
var c = 3;
alert(c);
};
}
aClass.aPublicMethod();
}
var entire = main.toString();
var body = entire.substring(entire.indexOf("{") + 2, entire.lastIndexOf("}"));
script.textContent = body;
document.getElementsByTagName("head")[0].appendChild(script);
“+ 2”之后需要entire.indexOf("{")
,以便不选择“{”字符,并且在脚本标记内容的开头没有空白的新行。
Javascript类函数不应该与我们保存类实例的变量同名,在Firefox aClass.aPublicMethod();
中只会在你第一次执行代码时自动调用(你不能覆盖类函数) ),Chrome不关心符号,它有效。
所以,我选择了AClass作为类名,使用了aClass作为类对象。
奇怪的是,当我们使用.toString()方法时,Firefox似乎正在以他喜欢的方式解析/显示函数,例如,当插入脚本时,Firefox Inspector中的内容将仅显示在一行中。 Firebug将在每个新行之前用“tab”空格格式化代码,即使我们在插入main()函数时删除了空格(由于Firebug知道在substring之前有main()函数,所以它添加了自动空间)。 Firebug在AClass()函数之前和之后都添加了一个新行;当函数返回值保存在变量中时,如aPrivateMethod或aPublicMethod,它显示在1行。 Firebug的另一个奇怪变化是var aClass = new AClass();
变为var aClass = new AClass;
。
function AClass()
{
// code
}
变为
function AClass() {
// code
}
依旧......
Chrome控制台始终尊重您在main()函数中编写的空格/新行。
我认为这是调试控制台的创建方式,并不重要。顺便说一句,在使用E4X扩展时,我所谈到的所有这些修改都不会出现在Firebug中。
使用function.toString()方法而不是E4X扩展时看到差异很有趣。也许有人有解释:))
使用function.toString()方法的Firefox控制台结果:
var aClass = new AClass; function AClass() { var a = 1; var aPrivateMethod = function () {var b = 2;alert(b);}; this.aPublicMethod = function () {var c = 34;alert(c);}; } aClass.aPublicMethod();
使用E4X扩展程序的Firefox控制台结果:
var aClass = new AClass(); function AClass() { var a = 1; var aPrivateMethod = function () { var b = 2; alert(b); }; this.aPublicMethod = function () { var c = 34; alert(c); }; } aClass.aPublicMethod();
使用function.toString()方法的Firebug结果:
var aClass = new AClass;
function AClass() {
var a = 1;
var aPrivateMethod = function () {var b = 2;alert(b);};
this.aPublicMethod = function () {var c = 3;alert(c);};
}
aClass.aPublicMethod();
使用E4X扩展程序的Firebug结果和使用function.toString()方法的Chrome控制台结果(不支持E4X)是相同的:
var aClass = new aClass();
function aClass() {
var a = 1;
var aPrivateMethod = function() {
var b = 2;
alert(b);
};
this.aPublicMethod = function() {
var c = 3;
alert(c);
};
}
aClass.aPublicMethod();
可以说是相关的,E4X是一种干净的方式,没有子串黑客但只支持Firefox:Creating multiline strings in JavaScript