I'm looking for a way to inject properties from "this" into local function scope, so i dont need write 'this.' when referencing to this properties.
Exact details are displayed in this code http://jsfiddle.net/wwVhu/3/, look at this part
...
//it's how it works
doStuff: function(param) { $('#output').html(this.value + param) }
//it's how i want it work - without referencing to this
//doStuff: function(param) { $('#output').html(value + param) }
I know it could be achieved by wrapping function code in "with(this) { ... }", but what are other options?
Writing "with(this)" in the beginning of every method or using js aop is what i'm trying to avoid.
Why would you want to do this? It's namespaced because it makes sence. this references to the element the listener is listening on. And it contains a lot more information than just the value.
If you want the value in another variable, you can do:
var value = this.value
There are basically four options:
You keep it the way it is. Context and local scope are different objects, combining them is bad practice and leads to collisions.
You add the value property as the 2nd parameter to the doStuff function.
You nickname this with a shorter identifier. I often find myself use $t.
You use with(this) $('#output').html(value + param);. This is a bad coding practice, as explained in 1). Your code becomes broken the second there is a param property in this.
Related
So I'm working on a sort of JavaScript framework, just some utility things for myself to use in future projects, and I want to make a data binding system.
The first method I used was objects, and the code would just loop through the specified html element and look for occurences of {{key}} in the markup and then look for that key in the object and replace it that way in the HTML.
For example, if you had <div>{{name}} is a cool guy</div> in the HTML and had {name:"joseph"} in the JS then the final product would be displayed on screen as 'joseph is a cool guy'.
However, I decided later to change my method and instead the framework would except a function. So instead of {name:"joseph"} you would give it function(){ var name = "joseph" }.
This obviously looks better and gives a lot better functionality.
I changed the processing function so instead of looking for the key/value pair to replace the {{key}}, it just uses eval on the variable to gets its value.
My problem lies here: How do I run my search/replace code INSIDE the scope of the function the user passes.
If the user defines variables within that function, their values will not be available anywhere else due to scope issues.
I've tried using Function.toString() to actually modify the source code of the function, but nothing's working and it's all very complicated.
(The issues are not due to the actual solution, I think that Function.toString() might work, but due to my implementation. I keep getting errors)
So... What is the best way to run arbitrary code in the scope of another function?
Critera:
Obviously, I can't modify the function because the user is passing it in. (you can't just tell me to add the search/replace code to the bottom of the function)
The variables must stay in the local scope of the function. (no cheating by using window.name = "joseph" or anything)
I am also aware of how terrible eval is so any suggestions as to get it to work are greatly appreciated. Thanks!
Code:
function process(html) {
var vars = html.match( /({{)[^{}]*(}})/g )
// vars = ['{{variable}}', '{{anotherVariable}}']
var names = vars.map( function(x){ return x.replace("{{", "").replace("}}", "") } )
// names = ['variable', 'anotherVariable]
obj = {}
for (var i = 0; i < names.length; i++) {
obj[names[i]] = eval(names[i])
}
for (var p in obj) {
html = html.replace(new RegExp('{{'+p+'}}','g'), obj[p]);
}
return html
}
You should go back to your first method with the object, it's much better. You can still pass a function, but the function should return an object:
function () {
return { name: 'joseph' }
}
I have a javascript function, I want to pass the function to another function and then:
identify all the global variables used within the function.
identify all the global function calls used within the function. [Harder]
Have this information returned in an obj.
Do this cleanly.
For instance:
function foo() {
var a; // ignored
global = 2; // want 'global'
bar(global); // want 'bar'
};
var obj = identifier(foo); // Need to write this function 'identifier'! :)
console.log(obj); // Produces: {globar:2, bar = bar()};
Note: I am looking for a clean way. I have considered turning the function to a string, parsing each line and processing it. I feel this might not be a fool proof plan and there will be a better way. If there is not a better way I'll come back and share my solution.
Thank you
You can use Esprima or another JS AST parser to turn the function into a clean structure. Then you can recursively analyse it. It is a bit too big to write as a StackOverflow answer, but in a nutshell, start with:
var ast = esprima.parse(foo);
Dive into .body, and recursively analyse it. Look for .type == "VariableDeclaration", that will contain local variables. Also take a look at .params of your function, those are also local. As you scan, look for .type == "Indentifier" and .type == "CallExpression"; those will use variables and functions, so check them against your list of local variables. You will need to do it in two passes, first to gather locals, then to find globals. Also, as you find .type == "FunctionDeclaration" or .type == "FunctionExpression", you have to make a new scope: move the local variables list into something like inherited locals, and make a new locals list, in order for the inner scope variables not to bleed into the outer scope.
Lots of details need to be ironed out; you can check ESTree project to see what node types are possible.
Lastly, I'd tentatively agree with zerkms: unless you are writing an editor or something similar, this is likely an XY-problem.
I'm looking for the standard way to calculate a variable once, then access it within the scope of every execution of a function, without relying on global variables.
This seems like a standard use of prototype properties (variables) - but every example I can find on JS prototypes is based on prototype methods (functions). The only thing I can find about setting properties / variables in a prototype is a question from someone who also couldn't find any information about these, asking if it's good or bad practice (tldr: it's fine, but remember it's rarely worth sacrificing readability for tiny performance gains).
I've got a way to set and get prototype properties that works, but feels clunky as it depends on a reference to the function (essentially var prop = thisfunctionname.prototype.someprop). Since I found it through trial and error, I'd like to ask if there's a cleaner, more standard way to get these prototype properties from within the function, without going back up to the scope around the function and getting the function from there?
Here's a simplified light-hearted example: an imaginary jQuery plugin that adds a number to another number then returns it in a sentence with the user's name. We want to ask the user their name only once, then store that name for re-use within scope:
(function($) {
var sum = function( num1,num2 ) {
var result = num1 + num2;
// This works, but seems clunky since it depends on the variable `sum`
// from the scope around this function - is there a better way?
var name = sum.prototype.name;
$(this).text( num1+' plus '+num2+' is '+result+', '+name+'.');
return $(this);
};
var name = prompt('Please enter your name','');
// Is there a better way to set this default variable to be accessible
// in all calls to this function?
sum.prototype.name = name;
$.fn.basicArithmetic = sum;
})(jQuery);
// end of plugin. Example usage...
$('<p/>').basicArithmetic(1,5).appendTo('body');
$('<p/>').basicArithmetic(2,2).appendTo('body');
$('<p/>').basicArithmetic(25,30).appendTo('body');
$('<p/>').basicArithmetic(92.3,15.17).appendTo('body');
Live jsbin example. More realistic real-life use cases would be when the calculation for the property is expensive in memory usage, or destructive (e.g. requires changing the DOM during calculation).
Two different answers, really:
The usual way is to use a variable within a scoping function (you already have one handy in your example); no prototypes involved at all.
(function($) {
var name;
name = prompt('Please enter your name','');
function sum( num1,num2 ) {
var result = num1 + num2;
$(this).text( num1+' plus '+num2+' is '+result+', '+name+'.');
return $(this);
}
$.fn.basicArithmetic = sum;
})(jQuery);
Updated JSBin Example | Source
(Side note: I also changed your anonymous function expression into a named function declaration, but it doesn't really matter in this case.)
The usual way in a jQuery plug-in is to store the data on the element(s) the plug-in is being applied to. That doesn't work for the example you gave, which requires that the data be global to the plug-in, but normally (not always, just normally) plug-ins keep only instance-specific information, which you'd normally store on elements (probably via the data function).
I'm wanting to directly update the object referred by a function argument from within the scope of that function. An example:
var thisObj = { "val" : "original value" };
function modFunc(objRef) {
objRef = { "val" : "modified" };
console.log(objRef); // { "val" : "modified" }
}
console.log(thisObj); // { "val" : "original value" };
I understand why this happens, and I realize that I could have used
objRef.val = "modified";
within modFunc to perform the modification. For reasons specific to my project though, I would like to be able to accomplish something like:
function modFunc(objRef) {
objRef.self = { "val" : "modified" }; // Of course this will not work,
// but is there an Object property or method that allows one to access
// the actual memory pointer being referenced by the variable?
}
where I can specify that I want to directly modify thisObj to reference the new object that I instantiate within modFunc. Is this possible? I know there are tools like Object.assign() that I could use to do this but it's not supported universally, or library tools like bind() that I could use if I imported the library, but it just seems like there might be some native syntax that would allow me to do this and I just haven't been able to find it?..
I've spent some time looking, otherwise I try not to ask questions like this. I also know there are other similar posts to this one, but nothing exactly like what I'm asking and I don't have the 'reputation' here to be able to respond directly to posts etc. so I didn't see an easy way to focus the discussion. Anyway, thanks for any help!
What you're asking for is, essentially, a call-by-reference mechanism, or the ability to explicitly create a reference to a variable. In JavaScript, that's not possible. You can (as you note) pass around references to objects and use those to modify object property values (and to add and remove properties, even), but that's not quite the same thing.
This would be true assignment by reference which javascript doesn't support. It only supports the false, misunderstood kind of assignment by reference.
since you cant deal with references, you can simply make objRef a global variable, and not pass it as an arg at all. then you're updating the original object.
I'm using mootools:
I can't figure out how to use a variable when using an addEvent.
I want to use a for next loop to set values in a loop:
for (x=0;x<num;x++){
var onclickText = 'function (){onclick="addPageMoveEvent('+x+'"); }';
$('pageNum'+x).addEvent('click', onclickText);
}
>
I've search forums but not found any help.
Any help would be great.
Thanks
The addEvent method in MooTools accepts two arguments:
myElement.addEvent(type, fn);
Arguments:
type - (string) The event name to monitor ('click', 'load', etc) without the prefix 'on'.
fn - (function) The function to execute.
It does not take a string and passing a string such as "myFunction()" or "function() { myFunction(); }" will not work.
Since you are inside a loop, and the variable x will share the environment, you need to wrap its value inside another closure. One way is to use an additional closure:
$("pagenum" + x).addEvent("click", (function(value) {
return function() { addPageMoveEvent(value); }
})(x));
See all questions on StackOverflow regarding this particular problem of creating closures within loops.
Also worth checking out is this MDC article - Creating closures in loops: A common mistake
Warning: this first example will not work! Read on for an explanation.
You are confusing onclick HTML syntax with the MooTools addEvent. Try
for (var x=0;x<num;x++){
$('pageNum'+x).addEvent('click', 'addPageMoveEvent('+x+');');
}
This is simpler and cleaner, but might still not do what you want. This code will call the function addPageMoveEvent every time the link is clicked... is that what you want?
Since MooTools doesn't allow the above method, you must use the following:
A programmatically more interesting and less hazardous way to do the same would be:
factory = function (x) { return function() { addPageMoveEvent(x); }; };
for (var x=0;x<num;x++){
$('pageNum'+x).addEvent('click', factory(x));
}
This uses a factory for creating closures that hold your values of x... rather complex code, but it's the purist way. It also avoids using the scary eval that occurs because you feed addEvent a string. (It seems that MooTools doesn't like the other option anyway.)
That a use case for mootools pass method.
for (x=0;x<num;x++){
$('pageNum'+x).addEvent('click', addPageMoveEvent.pass(x));
}
Pass internally creates a closure that holds x in the his scope, so when the click event is fired it has the right value cause its not the same from the for loop.