I'm working on a debugger that injects code into already existing code. Which then use eval() to log and run it.
However eval() seems to work in only its existing scope. To overcome this I tried to add a class that i recreated in each local scope. But it doesnt work.
I've added code to ilustrate my problem. The first alert works as expected, I'm assuming that it is because MyClass is created in the same scope.
The second alert still display b as 10 even though I've set b in local scope to 20 inside the TestC function. And the last alert doesn't work at all eval() returns in console "Uncaught ReferenceError: c is not defined".
If I add the whole MyClass inside each function and the assign it, then it works, but that doesn't feel like an elegant solution. And can add 1000's of lines of code to a project.
http://jsfiddle.net/ekim/zryj3taq/2/
var MyClass = function()
{
this.MyAlert = function(codex)
{
eval(codex);
}
}
var b = 10;
var MyOne = new MyClass();
MyOne.MyAlert("alert(b);");
function TestC()
{
var b = 20;
var MyOne2 = new MyClass();
MyOne2.MyAlert("alert(b);");
var c = 20;
var MyOne2 = new MyClass();
MyOne2.MyAlert("alert(c);");
}
TestC();
You can use new Function(\[arg1\[, arg2\[, ...argN\]\],\] functionBody)
(function(){
var str = "return (A+B)*C";
var myFunc = new Function("A","B","C", str);
var result = myFunc(2,3,4);
console.log(result);
}());
/* Example with function */
(function(){
var fncDouble = function (X) {
return X*2;
}
var str = "return F(A)+B";
var myFunc = new Function("F","A","B", str);
var result = myFunc(fncDouble,3,1);
console.log(result);
}());
As far as I know, there is no easy solution to this, as the eval() function just creates a new, separate compiler.
Try this: MyOne2.MyAlert.call(this, "alert(b)");
Related
So I can define a property on a function from the outside such as: createNewPerson.hmm = 3; and I get the result 3 when I use the alert. However if I try to do the same but from within a function (as in define a property within a function) it doesn't work.. I tried all the commented lines below. Is there a different way to achieve this or is it simply not possible? If it's not possible, then how does javascript append the .hmm property to the function and later call it?
Full code:
function createNewPerson(name) {
//var hello = "hgfgh";
//hello: "hgfgh"
//hello = hgfgh;
//this.hello = hgfgh;
}
createNewPerson.hmm = 3;
alert(createNewPerson.hmm);
alert(createNewPerson.hello);
I think you are trying to create objects. In javascript, you do it this way:
function Test(){
this.foo = "bar";
this.func = function(){
console.log(this.foo);
}
}
const test = new Test();
test.foo = "baz";
test.func(); //Will print "baz".
note the use of "new". This is what enables the mechanism of allowing code to modify properties of object. The modified values of the properties is then accessible by the object itself.
Hi please try below code,
jsFiddle
function createNewPerson(name) {
//var hello = "hgfgh";
//hello: "hgfgh"
//hello = hgfgh;
this.hello = "hgfg";
this.name = name;
}
var cnp = new createNewPerson('de');
cnp.hmm = 3;
alert(cnp.hmm);
alert(cnp.hello);
alert(cnp.name);
Assume I have this example file called import.js
var self;
function Test(a,b){
this.a = a;
this.b = b;
self = this;
}
Test.prototype.run = function(){
console.log(self.a, self.b)
}
module.exports = Test
When I require the file and create one new 'object' everything works perfectly, but when I create a 2nd object, they both have access to self, only the latter one works.
var Test = require('./import.js');
var one = new Test(1,2);
one.run()
1 2
var two = new Test(3,4);
two.run()
3 4
one.run()
3 4
Is there a way to re-require the file such that it creates separate scopes?
Putting it as two different variables doesn't work,
var Test1 = require('./import')
var Test2 = require('./import')
var one = new Test1(1,2);
var two = new Test2(3,4);
one.run()
3 4
But duplicating the file does exactly what I am looking for..
var Test1 = require('./import1');
var Test2 = require('./import2');
var one = new Test1(1,2);
var two = new Test2(3,4);
one.run();
1 2
Yes re-writing self into this would work but, But is this possible without modifying the import.js file, or duplicating it?
Answering my own question here, but there are at least two ways this is possible....
(1) Deleting Cache
How to remove module after "require" in node.js?
var Test1 = require('./import.js');
delete require.cache[require.resolve('./import.js')]
var Test2 = require('./import.js');
var one = new Test1(1,2);
var two = new Test2(3,4);
one.run()
1 2
two.run()
3 4
Doesn't even look that messy, although it's grossly inefficient and would get costly very fast to write code this way...
(2) Using function Scope
Because require reads the file and then runs it,
var Test = require('./test.js');
is equivelent to
var Test = eval( fs.readFileSync('./test.js', 'utf8') );
So, if instead of using require, you read the file you can establish new scopes inside of functions:
var fs = require('fs');
var File = fs.readFileSync('./import.js', 'utf8');
var Test1, Test2;
(function(){ Test1 = eval(File); })();
(function(){ Test2 = eval(File); })();
The self inside the file would now be stored inside the function scope you created. so once again:
var one = new Test1(1,2);
var two = new Test2(3,4);
one.run()
1 2
two.run()
3 4
Slightly messier, but far faster then deleting the cache and re-reading the file every time.
In short, it is not possible to do this without modifying import.js file or duplicating the file. This is because self is a global variable for that document, which will be the same for every instance of the function object.
Alternative #1
The problem is that you assign self to a global variable. Both of these have access to the same variable and therefore you get the observed results. Also, your use of self is unneccessary. The code below works as you described.
function Test(a,b){
this.a = a;
this.b = b;
}
Test.prototype.run = function(){
// Simply using 'this' to access the properties of the function is sufficient - no need for self
console.log(this.a, this.b)
}
module.exports = Test
Working example
In this case with each new Test() instance you will have a separate instance, so you will not need to 're-require' the files.
Alternative #2
If you want to keep self as per your edit, another option would be to just rewrite the function you want to call. For example:
var Test = require('./import.js');
Test.prototype.run = function(){
console.log(this.a, this.b)
}
If this is also not an option, then you need to provide more information as to what you can or cannot do.
I'm trying to learn some OOP, so bear with me. I need to use a variable I defined in one function, elsewhere. Here is my example code (I want INTERCEPT!! to be logged, but it returns undefined):
function Talk() {
var greeting;
var pleaseStop; // declare it
this.A = function () {
greeting = 'hello';
console.log(greeting);
var intercept = function () {
pleaseStop = 'INTERCEPT!';
}
}
this.B = function () {
greeting = 'goodbye';
console.log(pleaseStop); // this returns undefined!
console.log(greeting);
}
}
var activateTalk = new Talk();
activateTalk.A();
activateTalk.B();
This whole code logs the following:
hello
undefined
goodbye
I have also tried intercept.pleaseStop() but it still returns undefined. Would anyone know of a solution?
EDIT:
I've removed the var the second time, but it still returns undefined:
http://jsfiddle.net/d654H/2/
var pleaseStop = 'INTERCEPT!';
You're declaring a new, function-local variable here; drop the var to assign to the existing variable in scope.
Then, you need to actually call intercept; at the moment you only define it.
It's your choice as to when you call that function; in this live example I simply do so immediately after the definition, for the purposes of exposition.
Remove var in front of the assignment to pleaseStop.
This assigns a new value to the pleaseStop declared inside the constructor, which is visible also from inside B:
var intercept = function () {
pleaseStop = 'INTERCEPT!';
}
This declares a new local variable pleaseStop, completely unrelated to the other pleaseStop, that is not visible outside intercept:
var intercept = function () {
var pleaseStop = 'INTERCEPT!';
}
If you do the latter instead of the former, you end up changing the value of another variable than the one you intended.
Your problem is you never set pleaseStop. You have declared intercept as a function, but you never called it. Therefore, pleaseStop is undefined.
Firstly you have't called intercept() anywhere and also u did something
var pleaseStop = 'INTERCEPT!';
which will create new variable instead of initializing global variable
You can do something like this
function Talk() {
var greeting;
var pleaseStop; // declare it
this.A = function () {
greeting = 'hello';
console.log(greeting);
var intercept = function () {
pleaseStop = 'INTERCEPT!';//changed
}
intercept(); //..Added
}
this.B = function () {
greeting = 'goodbye';
console.log(pleaseStop); // this returns undefined!
console.log(greeting);
}
}
var activateTalk = new Talk();
activateTalk.A();
activateTalk.B();
Without var keyword.
var pleaseStop = "A";
function foo(){
pleaseStop = "B"; // overwriting to "B"
}
foo();
alert(pleaseStop); // shows "B"
With var keyword.
var pleaseStop = "A";
function foo(){
var pleaseStop = "B"
// This defines a new variable 'pleaseStop'
// in the scope of function foo(){}.
}
foo();
alert(pleaseStop); // shows "A"
Variable Scope
JavaScript has function-level scope. In most languages which have block-level variable scope, variable are accessible whithin their block surrounded by curly brackets ({and}). But JavaSciprt doesn't terminate scopes at the end of blocks, but terminate them at the end of functions.
I'm sure there are many articles and documents about it. I googled it and found an intresting introductory article.
http://javascriptissexy.com/javascript-variable-scope-and-hoisting-explained/
Hope this helps.
I am new to programming and I am stuck. Here is my code:
function Subtraction() {
var a = document.getElementById('inputA').value;
var b = document.getElementById('inputB').value;
var c = (parseFloat(a) - parseFloat(b)).toFixed(5);
alert(c);
}
This works fine to me, but I have many functions that waits for onclick event to be executed. And every function have the same a and b variables. How can I get them in global scope so I don't need to wait them over and over again? I tried to put them outside of the function, but what event can trigger their declaration? There is what I tried:
var a = document.getElementById('inputA').value;
var b = document.getElementById('inputB').value;
parseFloat(a).toFixed(5);
parseFloat(b).toFixed(5);
function Subtraction() {
var c = a - b;
alert(c);
}
I see two options at least:
One is to declare them after window has loaded.
Other is to pass the elements as function parameters:
1
var a,b;
window.onload = function(){
a = document.getElementById('inputA').value;
b = document.getElementById('inputB').value;
}
2
element.onclick = function(){
var a = document.getElementById('inputA').value;
var b = document.getElementById('inputB').value;
Subtraction(a, b);
};
Btw, capital letters is used for Classes, if its a normal function better to use small "s".
You can try to declare the vars in a different javascript source file or put them in an upper block the environment of the variables holds through the entire execution from the moment you declare them so if you do this:
<script src="declare_vars.js"></script>
<script src="use_vars.js"></script>
In declare_vars.js you can try doing:
var a;
var b;
and in the other scripts use them as you want and give them the values you need, they will always be available.
The value of an input is a primitive (specifically a string) and is therefore passed by value. This means that if you do this:
var oldvalue = document.getElementById('someinput').value;
document.getElementById('someinput').value = "derp";
alert(oldvalue); // it has not changed
What you can do, if you want, is cache the result of getElementById:
var inputA = document.getElementById('inputA');
var inputB = document.getElementById('inputB');
// in your function {
var c = parseFloat(inputA.value)-parseFloat(inputB.value);
// }
This works because the result of getElementById is the input element itself. You then retrieve the desired property of this element (.value) at the specific time you need it.
That said, avoid global variables. Put variables in a scope if you want, but don't make them global.
Disclaimer: this solution makes no attempt to avoid using global variables. The usage of global variables may introduce all sorts of problems, though for an application as simple as the one described by the OP the potential pitfalls are limited.
You can add the initialization in the change event handler of each input to make sure it is always up to date:
HTML
a<input id="inputA"/>
b<input id="inputB"/>
<button id="sum">sum</button>
JAVASCRIPT
var a,b;
document.getElementById('inputA').addEventListener('change',function(evt){
a = +evt.target.value;
});
document.getElementById('inputB').addEventListener('change',function(evt){
b = +evt.target.value;
});
document.getElementById('sum').addEventListener('click', function(evt){
console.log('Sum is ' + (a+b));
});
DEMO: http://jsbin.com/EZECEraR/2/edit
var A = function(x){
var that = this;
this.a = x;
}
A.prototype = {
init: function(){
alert(this.a); // as that is not found :s
}
};
var a = new A(1);
var b = new A(2)
a.init.call(b);
// I want to alert number 1, how to do it?
I need this because I use jQuery events.
my sick solution... not so good
I got my question answered but this has some problems, I have to define a local that var and create a closure for every event... sick!
var that = this;
this.view.skinAppliedSignal.add(function(){
that.onSkinApplied();
});
// then in the onSkinApplied the this is correct. any way not so hacky to get this done?
You cannot do that, in general. The only this that exists when a function runs is the this established by the invocation.
You can "trap" things in a closure when you establish event handlers:
function something() {
$('.whatever').each(function() {
var whatever = $(this);
whatever.find('button').click(function() {
whatever.hide();
});
});
}
In that example, "whatever" is used to save the element from the "each" loop so that the event handlers hooked up to button elements can get access to it.
edit — Based on a comment and the update to the question, it's clear that perhaps what's desired is something like the ".bind()" function that's part of ES5 (and which is supplied by some libraries, like Prototype, Functional, and jQuery). By using "bind", you basically wrap any function of your choice up in another function, such that your function will always be called with this set to some specific object.
Can't be done with a prototype. You could do it this way, however:
var A = function(x){
var that = this;
this.a = x;
this.init = function(){
alert(that.a);
}
}
var a = new A(1);
var b = new A(2)
a.init.call(b);