I have some function defined inside a function, but set to global:
function someFn(someVar) {
var arr = makeArray(someVar);
// global function:
foo = function(bar) {
return arr.indexOf(bar)==-1;
}
}
When I debug with chrome console:
> foo
function (bar){return arr.indexOf(bar)==-1;}
can I get, without changing the source code, the content of arr?
Let's assume I can't just get and execute the commands by which arr was generated, because I don't know the last value of someVar.
The variable has to be somewhere in the memory, because when I call the function, it can be accessed, but what name does it have? I already tried:
> foo.arr
undefined
X-Y problem response; I don't know how you could access arr from the console, but I can give you a few tips to debugging via a breakpoint, even if the code is minified.
Try using Google Chrome, and in Debugger, click the {} icon below the code window. That will pretty-print the script, though the varnames will still be minified. (_a1 = new_43` etc.)
Next is the art of reading minified code; Code minifiers can't change anything that is accessed via a string; the most signature of which are object properties (anything after a .). It also helps that without whitespace, it becomes easier to find a particular sequence of symbols. You could try CTRL-Fing for terms like .indexOf, ==-1, etc. If this is an actual corporate-released library, chances are you can go beyond your little example and refer to things like myCompanyLibrary.dockInstance.locator=.
Once you find that line, you can put a breakpoint there. Good luck!
Related
In Javascript, local variables do not live on any object that I'm aware of. That is,
function foo() {
const x = 2;
self.x; // undefined
this.x; // undefined
window.x; // undefined
x; // 2, obviously
eval('x'); // 2
}
The last option eval('x') shows that it is possible to refer to these variables by name. I'm looking to extend this and access a variable using a name pattern:
function foo() {
// Code not under my direct control
function foobar_abc() {}
function other_functions() {}
// Code under my control
const matchingFunction = // find the function with name matching 'foobar_*'
}
If this lived on an object, I would use something like myObject[Object.keys(myObject).find((key) => key.startsWith('foobar_'))]. If it were in the global scope, myObject would be window and everything works.
The fact that eval is able to access the variable by name implies that the value is available somewhere. Is there any way to find this variable? Or must I resort to techniques which re-write the (potentially very complex) code which is not under my direct control?
I'm targeting modern browsers, and in this use case I don't mind using eval or similarly hacky solutions. Arbitrary code is already being executed, because the execution of user-provided code is the purpose.
Another option is to use code parsing to deduce the function names using a javascript AST (abstract syntax tree) library. The "esprima" package will probably be good place to look:
https://www.npmjs.com/package/esprima
So you can do
import esprima from 'esprima'
const userCodeStructure = esprima.parseScript( userProvidedJavascriptString );
const allTopLevelFunctionDeclarations = userCodeStructure.body.filter( declaration => declaration.type === "FunctionDeclaration" );
const allTopLevelFunctionNames = allTopLevelFunctionDeclarations.map( d => d.id );
I haven't tried this myself by the documentation suggests it should work (or something like it):
http://esprima.readthedocs.io/en/latest/
One possible approach that might help you here is to evaluate at global scope rather than in a function, and that might put the functions on the window object instead of in local scope.
Easiest way to do this is probably to write a new tag into the document and inject the user-provided code.
Relying on variable names is the wrong approach.
eval is evil. It may not be available under CSP. Considering that the code is supposed to run in browser, the biggest problem is that variables don't have expected names in minified code. They are a, b, c...
In order to maintain their names, they should be object properties - and so they will be available on the object.
Or must I resort to techniques which re-write the (potentially very complex) code
This is refactoring and that's what should be done to avoid bad code that smells and creates major problems.
I have the following code that I am trying to use to register a callback on an array of buttons. But I cannot seem to understand how I can bind the strings that I would need in the callback. Any suggestions would be much appreciated!
for (var i = 0; i < this.car_types.length; ++i) {
this.select_car_buttons.push($("#button_select_car_" +
this.car_types[i].car_type));
this.select_car_buttons[this.select_car_buttons.length - 1]
.click(function() {
console.log(this.car_types[i].car_type);
}.bind(this));
}
Somehow the this object is the button itself and not the object under whose scope the function is called.
EDIT : It seems like the this object was indeed being passed in properly. The issue is that the variable i is not going out of scope and is being captured by reference not by value. How should I go about solving this problem?
Also there seem to lots of such issues with JavaScript as a language (at least things that can be classified as an issue considering the semantics employed by the traditional C family languages such as C and C++ to be correct), is there some article I can read that warns me against these types of issues?
ANOTHER EDIT : On trying making a closure with the value of i captured by value I tried the following code
this.select_car_buttons[this.select_car_buttons.length - 1]
.click((function(scoped_i) {
return function() {
console.log(this.car_types[scoped_i].car_type);
}.bind(this);
}(i)));
But I get the following error in Safari
TypeError: undefined is not an object (evaluating 'scoped_i')
EDIT : The same code works in Firefox and Chrome but not in Safari!
This is a scope issue. For modern browsers (that support ES6) you could just change var to let in your for loop and it would get fixed.
for (let i = 0; i < this.car_types.length; ++i)
Quoting the MDN docs
The let statement declares a block scope local variable, optionally initializing it to a value.
For more global support (non ES6 support) use an immediately invoked function to create extra scope for the variable (which you will pass as a parameter)
this.select_car_buttons[this.select_car_buttons.length - 1]
.click((function(scoped_i) { // IIF starts here, the new variable is called scoped_i for verbosity
return function() { // your original function code goes here
console.log(this.car_types[scoped_i].car_type); // use the newly scoped variable
}.bind(this);
}.bind(this)(i))); // end and execute the IIF while passing the i variable to it
Yes, this structure do make a lot of closures and make code very hard to read. Since you use jQuery, there are a much better way to solve this problem which saves the data in html:
html:
<button class="select-car" data-car-type="CarA">Select CarA</button>
<button class="select-car" data-car-type="CarB">Select CarB</button>
<!-- And a lot of buttons -->
js:
var selectCarOnClick = function() {
console.info($(this).data('car-type'));
};
$('button.select-car').click(selectCarOnClick);
Live exmaple: http://codepen.io/SCLeo/pen/VaQYjW
If you have a lot of other information to store and you want to use a object to store them instead of DOM, you can save car-name or car-id instead of car-type.
Here is the document about $.data: https://api.jquery.com/jquery.data/
First of all i know that:
Use of the with statement is not recommended, as it may be the source
of confusing bugs and compatibility issues. See the "Ambiguity Con"
paragraph in the "Description" section below for details.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/with
BUT
If we take a simple function like this (THIS FUNCTION WORKS GREAT)
function loadImage(url,cb){
with(new Image)
onload=cb,
src=url
}
we notice there is nothing CONFUSING that could break the code inside the function closures. the only 2 variables we use are onload & src. Until i don't create variables, objects,arrays or functions that i name onload or src nothing bad should happen.
Said that, my question is:
The javascript garbage collector should add the new Image to the collection directly after been executed ?
And so have less impact to the memory vs a standard function:
function loadImage(url,cb){
var image=new Image;
image.onload=cb;
image.src=url;
}
In the above case the var image remains inside the function until i execute a new one.
btw. also the code would be much shorter.
// preload a image
function loadImage(a,b){with(new Image)onload=b,src=a}
// convert a file to base64
function readFile(a,b){with(new FileReader)onload=b,readAsDataURL(a)}
A demo to play with
http://jsfiddle.net/5wqm3/4/
First of all i know that: Use of the with statement is not recommended, as it may be the source of confusing bugs and compatibility issues
No, the main issue with the with statement is that it prevents certain static optimisations as it introduces new variable names at runtime. That's also the reason why it was forbidden in ES 5 strict mode code.
Using the with statement should have less impact to the memory vs a standard function
No. They perform exactly the same. When the function ends, the new Image/image is no more in scope of anything. The image variable will be gone in the same way as the with statement ends with a closing brace.
The javascript garbage collector should add the new Image to the collection directly after been executed?
Actually, I don't think the object is garbage-collected. It's a DOM element with an alive load handler waiting for it, I would assume it is still referenced from the event loop queue. However, that doesn't really matter for your question I think.
To create an IDE that would autocomplete all variables the user declares but would be oblivious to other variables such as Math.PI or even the module Math, the IDE would need to be able to identify all identifiers relating to variables declared by the user. What mechanism could be used to capture all such variables, assuming you already have access to the AST (Abstract Symbol Table) for the program?
I am using reflect.js (https://github.com/zaach/reflect.js) to generate the AST.
I think it's pretty much impossible
Here is why I think it's pretty much impossible without executing it:
Let us go through the unexplored parts, from easy to hard.
Easy to catch:
Function scope is missed here:
(function(x){
//x is now an object with an a property equal to 3
// for the scope of that IIFE.
x;
})({a:3});
Here is some fun dirty tricks for you all.:
Introducing... drum roll... Block Scoping!!
with({x:3}){
x;//x is now declared in the scope of that with and is equal to 3.
}
try{ throw 5}catch(x){
x // x is now declared in the scope of the try block and is equal to 5;
}
(people reading: I beg you to please not use these last two for actual scoping in code :))
Not easy:
Bracket notation:
var n = "lo";
a["h"+"e"+"l"+n] = "world"; // need to understand that a.hello is a property.
// not a part of the ast!
The really hard parts:
Let us not forget invoking the compiler These would not show up in the AST:
eval("var x=5"); // declares x as 5, just a string literal and a function call
new Function("window.x = 5")();// or global in node
In node.js this can also be done with the vm module. In the browser using document.write or script tag injection.
What else? Of course they can obfuscate all they want:
new Function(["w","i","n","dow.x"," = ","5"].join(""))(); // Good luck finding this!
new Function('new Function(["w","i","n","dow.x"," = ","5"].join(""))()')();// Getting dizzy already?
So what can be done?
Execute the code, once, in a closed, timed environment when you update the symbol table (just the relevant parts)
See what's the generated symbol table is from the execution
Boom, you got yourself a symbol table.
This is not reliable but it's probably as close as you get.
The only other alternative I can think of, which is what most IDEs are doing is to simply ignore anything that is not:
object.property = ... //property definition
var a = ... //scoped
b = ... //global, or error in strict mode
function fn(){ //function declaration
object["property"] //property with a _fixed_ literal in bracket notation.
And also, function parameters.
I have seen no IDE that has been able to deal with anything but these. Since they're the most common by far, I think it's perfectly reasonable to count those.
By adding them onto am object that already exists....ie
window.mynewvar = 5;
function mynewfunc() {
}
I prefer to declare one Javascript file for my all website. I am trying to decrease the usage of global variables. My examples at the below, in both case each object has a myName field.
I would like to know when they are initialized?
And In terms of memory and efficiency which one is more effective?
For variable a, is declaring a.myName the same as global "var myName = Rebecca" ?
var a = {
myName : 'Rebecca' ,
sayHello : function() {
console.log(this.myName);
}
};
var b = {
myName : function() {
return 'Rebecca';
},
sayHello : function() {
console.log(this.myName());
}
};
Thanks
I believe these will be initialized identically (i.e. when the code is reached). What's different is what's happening when they are initialized and where the load is placed when their data is actually required.
To me, it would depend a lot on what you were expecting to have in myName. If it were just a string, I'd avoid the function and go with choice a. On the other hand, if there were a great deal of logic involved and that logic might not need to be invoked (for example, if it only gets executed when a user clicks on a button or the application reaches a certain state), I'd go with choice b. As I understand it, the function does consume memory and won't get garbage collected (which is a minus), but it also won't consume CPU resources until it's actually needed (which can be a huge plus).
I'm not sure I understand the question, but I'd say it's not the same. If the only member of a is myName then the two are equivalent (both are occupying the global namespace. But if you have multiple properties, the savings become obvious. From your examples, I think it's clear you understand this, so again I may not understand the question.
They will be initialized when the statements are first encountered. In a, 'Rebecca' is initialized as the value for the myName key. In b, it's just data internal to the myName (anonymous) function. a will be slightly more efficient because it avoids a function call. I also find it more readable in this simple example.
I find the choice to put everything in a single file questionable. In some cases, you want a modular design. And since you're worried about efficiency (albeit perhaps prematurely), note that having one big file can actually hurt performance if pages include code they don't need.
1) They are initialized when the script is processed in the browser, unless you declare the objects in an event handler. In that case the object is created when the event script is executed.
2) In terms of efficiency, a will probably be more efficient. Note though that in the first case you use a.myName and in the second b.myName() to get the value of the property.
3) No. If you assign a value to a property of an object, you always have to get that value through the object. In this case either a.myName or a['myName'].
a doesn't make any sense, because you're logging a function reference. B is the way to go, since you're actually invoking the method, using ().