In Firefox’s and Chrome’s consoles, this works (alerts script content):
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);
Using this code as a Greasemonkey script for Firefox works too.
Now, if want to add a “private method” do() to test() It is not working anymore, in neither Firefox/Chrome console nor in a Greasemonkey script:
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);
To make this work in a Greasemonkey script, I have to put all the code in a CDATA tag block:
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);
This is only works in a Greasemonkey script; it throws an error from the Firefox/Chrome console. I don’t understand why I should use a CDATA tag, I have no XML rules to respect here because I’m not using XHTML.
To make it work in Firefox console (or Firebug), I need to do put CDATA into tags like <> and </>:
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);
This doesn’t working from the Chrome console. I’ve tried adding .toString() at the end like many people are doing (]]></>).toString();), but it’s useless.
I tried to replace <> and </> with a tag name <foo> </foo> but that didn’t work either.
Why doesn’t my first code snippet work if I define var do = function(){} inside another function?
Why should I use CDATA as a workaround even if I’m not using XHTML?
And why should I add <> </> for Firefox console if it’s working without in a Greasemonkey script?
Finally, what is the solution for Chrome and other browsers?
EDIT:
My bad, I’ve never used do-while in JS and I’ve created this example in a simple text editor, so I didn’t see “do” was a reserved keyword :p
But problem is still here, I’ve not initialized the Javascript class in my examples.
With this new example, CDATA is needed for Greasemonkey, Firefox need CDATA between E4X <> </> and Chrome fails:
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);
Question: why?
All rights to @BrockAdams Why is CDATA needed and not working everywhere the same way? for the idea to write everything in a function and insert content into the script tag, thanks.
Thanks to @polygenelubricants javascript get function body for getting the main() function content only and not the function with its content.
“+2” after
entire.indexOf("{")is needed for not selecting “{” character and not having a blank new line at the beginning of the script tag content.The Javascript class function should not have the same name as the variable where we save the class instance, in Firefox
aClass.aPublicMethod();will only be called automatically the first time you execute the code (you can’t override class function), Chrome don’t care of the notation, it works.So, I’ve choosed AClass for the class name and aClass for the class object.
Curiously, it seems Firefox is parsing/displaying the function the way he likes when we use .toString() method, for example when script is inserted, its content in Firefox Inspector will be shown in one line only. Firebug will format the code with a “tab” space before each new line even if we remove the spaces when inserting the main() function (due to the fact Firebug know there was the main() function before substring so it adds auto-space). Firebug adds a new line too before and after AClass() function; when function return value is saved in variable, like aPrivateMethod or aPublicMethod, it’s displayed on 1 line. Another weird change with Firebug is that
var aClass = new AClass();becomesvar aClass = new AClass;.becomes
and so on…
Chrome console always respect the spaces/new lines like you’ve written in the main() function.
I think it’s the way debug console have been created and it has no importance. By the way, all this modifications I’ve talked about doesn’t appear with Firebug when using E4X extension.
It’s funny to see the difference when using function.toString() method instead of the E4X extension. Maybe someone has an explanation 🙂
Firefox console result with function.toString() method:
Firefox console result with E4X extension:
Firebug result with function.toString() method:
Firebug result with E4X extension and Chrome console result with function.toString() method (E4X not supported) are the same:
Can be related, E4X is a clean way to do this, without substring hack but only supported by Firefox: Creating multiline strings in JavaScript