Inject variables into function scope - javascript

Ho do i call a function injecting into its scope arbitrary variables / functions? I want to define an "update" function that can freely call a series of functions, but they have to be defined and bond in another scope.
I tried with with but it doesn't work.
Also, I know there are a tons of solutions like passing the object whose functions to call or define a list of arguments and bind them, but since "update" has to be defined by the user, its signature must be just a simple function with no arguments (just like in the code below) but it has to have access to a long list of functions with an arbitrary binding.
So basically: the update() function must not contain any argument in its signature and within it the functions have to be callable just with their names (no this.printSize(), obj.printSize() and so so).
function obj (size) {
this.printSize = function () {
console.log(size);
}
}
const obj1 = new obj(1);
const obj2 = new obj(2);
function update () {
printSize();
}
with(obj1) {
update();
}
with(obj2) {
update();
}

Viewer discretion is advised:
function evalWith(obj, func) {
with(obj) return eval('(' + func + ')')();
}
// Example:
function obj(size) {
this.printSize = function() {
console.log(size);
}
}
const obj1 = new obj(1);
function update() {
printSize();
}
evalWith(obj1, update); // 1

Variable binding in javascript is set upon function creation, not calling.
So, your only effective options are to namespace the variables you need in an object, and populate that later. Or you can set the variables to the global namespace (e.g) window.
There's no way to get the contents of a function and re-eval it later, unfortunately.
The most you can do is change the values of the arguments passed into the function, using call or apply as mentioned by others.

Have you tried
function obj (size) {
this.printSize = function () {
// presumably do something with "this"
console.log(size);
}.bind(this);
}

You will need to make an instance of the obj before each with call
function obj (size) {
printSize = function () {
console.log(size);
}
}
function update () {
printSize();
}
const obj1 = new obj(1);
with(obj1) {
update();
}
const obj2 = new obj(2);
with(obj2) {
update();
}

Related

Calling a nested function by name

I am looking for a way how to call a nested function when I have its name as string. I am writing a function that returns an object that will do some processing by calling functions that are part of its closure and are intentionally inaccessible from the global scope. The code goes something like this:
function makeHandler() {
function case1() {
...
}
function case2() {
...
}
let handler = {}
handler.handle = function(div) {
let divCase = div.getAttribute("data-case");
//divCase is now either "case1" or "case2". I want to call the correct function. I have:
({case1: case1, case2: case2}[divCase])()
}
return handler
}
let h = makeHandler()
h.handle(someDiv)
I find this approach unsatisfying, if I add case3 I will have to update the handle function. I'd think that the functions case1 and case2 must be part of some context, just like makeHandler is part of the global context and accessible as property of the window object.
I am aware of the very similar 10 year old question: Calling nested function when function name is passed as a string and I've seen other articles with similar recommendation to what I am doing -- create an object where properties are function names and values are functions themselves. I am looking for a more 'generic' solution.
I like using this pattern:
function makeHandler() {
const cases = {
case1: function () {},
case2: function () {}
}
let handler = {}
handler.handle = function(div) {
let divCase = div.getAttribute("data-case");
if (!cases[divCase]) throw 'bad case name';
cases[divCase]();
}
return handler
}

Newly created objects call to constructor undefined if constructor is inside another function

I just learned OOP and there is one little thing that I am not able to solve. The problem is a scope issue of some sort.
If I create a new object then how will I be able to give it access to my constructor function if the constructor function is inside another function? Right now I get undefined. Storing the function in a global variable wont do the job.
var example = new something x(parameter);
example.i();
var getFunction;
var onResize = function() {
getFunction = function something(parameter) {
this.i= (function parameter() {
// Does something
});
};
};
window.addEventListener('resize', onResize);
onResize();
For OOP javascript, the pattern should be like this.
//defining your 'class', class in quotes since everything is just functions, objects, primitives, and the special null values in JS
var Foo = function (options) {
// code in here will be ran when you call 'new', think of this as the constructor.
//private function
var doSomething = function () {
}
//public function
this.doSomethingElse = function () {
}
};
//actual instantiation of your object, the 'new' keyword runs the function and essentially returns 'this' within the function at the end
var foo = new Foo(
{
//options here
}
)
If I understand you, you want to know how to access variables inside another function. Your attempt is reasonable, but note that getFunction is not bound until after onResize is called. Here's a bit of a cleaner demo:
var x;
function y() {
// The value is not bound until y is called.
x = function(z) {
console.log(z);
}
}
y();
x('hello');
A common JavaScript pattern is to return an object that represents the API of a function. For example:
function Y() {
var x = function(z) {
console.log(z);
}
return {
x: x
};
}
var y = Y();
y.x('hello');
You should definitely read up on the basic concepts of JavaScript. Your code and terminology are both sloppy. I'd recommend Secrets of the JavaScript Ninja. It does a good job explaining scope and functions, two tricky topics in JavaScript.

How to dynamically build a function in javascript

I want to create a function dynamically using javascript. I've started with the following:
function setFunc(setName){
var setName = function () {
};
}
setFunc("totop");
I want to set a function dynamically, but it doesn't work!
How can I fix this?
That won't work.
However, consider this: functions in JavaScript are just values and window is the top-level scope, so... (This assumes it is desired for the new function to be created in the top-level scope.)
function setFunc (name) {
window[name] = function () { alert("hi!") }
}
setFunc("a")
window.a() // "hi!" - explicit property access on object
window["a"]() // "hi!" - ditto
a() // "hi!" - window implicit as top-level
However, I do not recommend this sort of global side-effect...
Happy coding.
The question is, in which context you want to create that function. If you really want to create a global function with that name, do it like
function setFunc( setName ) {
this[ setName ] = function() {
alert('I am ' + setName);
};
}
setFunc('totop');
However, this is not a great idea to clobber the global object like that. Furthermore, the above code will break in es5 strict mode. However, by using the new keyword, you could create constructs like
new setFunc('foobar').foobar();
or just store the result in a variable
var myObj = new setFunc('BoyohboyWhatALongString');
console.log( myObj ); // BoyohboyWhatALongString() is in there now
Don't Use the eval function like this:
function setFunc(setName){
eval (setName + " = function () { };");
}
setFunc("toTop");
You can access the window scope as an associative array and define the function with that name:
function setFunc (name) {
window[name] = function () { }
}

JavaScript function declaration

Are the JavaScript code snippets given below some sort of function declaration? If not can someone please give an overview of what they are?
some_func = function(value) {
// some code here
}
and
show:function(value){
// some code here
}
There are six ways/contexts in which to create functions:
1) Standard declarative notation (most familiar to people with C background)
function foo() {}
All the rest are function expressions:
2) As a method of an object literal
var obj = {
foo: function() {}
};
3) As a method of an instantiated object (created each time new is exectued)
var Obj = function() {
this.foo = function() {};
};
4) As a method of a prototype (created only once, regardless of how many times new is executed)
var Obj = function() {};
Obj.prototype.foo = function() {};
5) As an anonymous function with a reference (same effect as #1) *
var foo = function() {};
6) As an immediately executed anonymous function (completely anonymous)
(function() {})();
* When I look at this statement, I consider the result. As such, I don't really consider these as anonymous, because a reference is immediately created to the function and is therefore no longer anonymous. But it's all the same to most people.
The first one is simply creating an anonymous function and assigning it to a variable some_func. So using some_func() will call the function.
The second one should be part of an object notation
var obj = {
show:function(value){
// some code here
}
};
So, obj.show() will call the function
In both cases, you are creating an anonymous function. But in the first case, you are simply assigning it to a variable. Whereas in the second case you are assigning it as a member of an object (possibly among many others).
First is local (or global) variable with assigned anonymous function.
var some_name = function(val) {};
some_name(42);
Second is property of some object (or function with label in front of it) with assigned anonymous function.
var obj = {
show: function(val) {},
// ...
};
obj.show(42);
Functions are first-class citizens in JavaScript, so you could assign them to variables and call those functions from variable.
You can even declare function with other name than variable which that function will be assigned to. It is handy when you want to define recursive methods, for example instead of this:
var obj = {
show: function(val) {
if (val > 0) { this.show(val-1); }
print(val);
}
};
you could write:
var obj = {
show: function f(val) {
if (val > 0) { f(val-1); }
print(val);
}
};
One way of doing it:
var some_func = function(value) {
// some code here
}
Another way:
function some_funct() {
}
Yet another way:
var some_object={};
some_object["some_func"] = function() {};
or:
var some_object={};
some_object.some_func = function() {};
In other words, they are many ways to declare a function in JS.
Your second example is not correct.
The first one is a function declaration assigned to a variable (at least it should be, despite the fact that it's missing the variable type declaration first), the second one is probably related to a object declaration.
They are called anonymous functions; you can read more about them here:
http://www.ejball.com/EdAtWork/2005/03/28/JavaScriptAnonymousFunctions.aspx
The first example creates a global variable (if a local variable of that name doesn't already exist) called some_func, and assigns a function to it, so that some_func() may be invoked.
The second example is a function declaration inside an object. it assigns a function as the value of the show property of an object:
var myObj = {
propString: "abc",
propFunction: function() { alert('test'); }
};
myObj.propFunction();
The first one...
some_func = function(value) {
// some code here
}
is declaring a variable and assigned an anonymous function to it, which is equivalent to...
function some_func (value) {
// some code here
}
The second one should look like this...
obj = {
show:function(value){
// some code here
}
}
// obj.show(value)
and equivalent to...
//pseudo code
class MyClass {
function show (value) {
// some code here
}
}
obj = new MyClass(); // obj.show(value)
Cheers

Extend Javascript Function passed as parameter

I have a javascript function (class) that takes a function reference as one paremter.
function MyClass ( callBack ) {
if (typeof callBack !== 'function')
throw "You didn't pass me a function!"
}
For reasons I won't go in to here, I need to append something to the function by enclosing it in an anonymous function, but the only way I've been able to figure out how to do it is by adding a public function to MyClass that takes the callBack function as a parameter and returns the modified version.
function MyClass () {
this.modifyCallBack = function ( callBack ) {
var oldCallBack = callBack;
callBack = function () {
oldCallBack(); // call the original functionality
/* new code goes here */
}
return callBack;
}
}
/* elsewhere on the page, after the class is instantiated and the callback function defined */
myCallBackFunction = MyClassInstance.modifyCallBack( myCallBackFunction );
Is it possible to make this work when passing the callBack function as a parameter to the class? Attempting to modify the function in this manner when passign it as a parameter seems to only affect the instance of it in within the class, but that doesn't seem like it's a valid assumption since functions are Objects in javascript, and are hence passed by reference.
Update: as crescentfresh pointed out (and I failed to explain well), I want to modify the callBack function in-place. I'd rather not call a second function if it's possible to do all of this when the class is instantiated.
Function objects don't provide methods to modify them. Therefore, what you want to do is impossible the way you want to do it. It's the same thing Jon Skeet likes to point out about Java: Objects are not really passed by reference, but instead a pointer to them is passed by value. That means that changing the value of an argument variable to a new one won't affect the original one at all.
There are only two ways to do what you want in call-by-value languages like Java and JavaScript: The first one would be to use the (function) object's methods to modify it. As I already stated, function objects don't have those. The other one is to pass the object of which the function object is a property as a second argument and set the appropriate property to a new function which wraps the old one.
Example:
var foo = {};
foo.func = function() {};
function wrapFunc(obj) {
var oldFunc = obj.func;
obj.func = function() {
// do some stuff
oldFunc.call(obj, _some_argument__);
};
}
wrapFunc(foo);
This works for global functions as well: they are properties of the window object.
As Javascript uses lexical scoping on variables the following is possible:
var modifiableCallback=function() { alert('A'); };
function ModifyCallbackClass(callback)
{
modifiableCallback=function() { callback(); alert('B'); };
}
function body_onload()
{
var myClass=new ModifyCallbackClass(modifiableCallback);
modifiableCallback();
}
This does what you want, however the function "modifiableCallback" must be referred to with the same name inside ModifyCallbackClass, otherwise the closure will not be applied. So this may limit the usefulness of this approach for you a little.
Using eval (performance may suffer a bit) it is also possible to make this approach more flexible:
var modfiableCallback1=function() { alert('A'); };
var modfiableCallback2=function() { alert('B'); };
var modfiableCallback3=function() { alert('C'); };
function ModifyCallbackClass(callbackName)
{
var temp=eval(callbackName);
var temp2=eval(callbackName);
temp= function() { temp2(); alert('Modified'); };
eval(callbackName + " = temp;");
}
function body_onload()
{
var myClass=new ModifyCallbackClass("modfiableCallback1");
modfiableCallback1();
myClass=new ModifyCallbackClass("modfiableCallback2");
modfiableCallback2();
myClass=new ModifyCallbackClass("modfiableCallback3");
modfiableCallback3();
}
I assume you are saving this callback somewhere... Any reason this won't work?
function MyClass ( callBack ) {
var myCallBack;
if (typeof callBack !== 'function')
throw "You didn't pass me a function!"
var oldCallBack = callBack;
callBack = function () {
oldCallBack(); // call the original functionality
/* new code goes here */
}
myCallBack = callback;
}
You want to do something like:
function MyClass () {
this.modifyCallBack = function ( callBack ) {
var oldCallBack = callBack;
callBack = function () {
oldCallBack(); // call the original functionality
alert("new functionality");
}
return callBack;
}
}
/* elsewhere on the page, after the class is instantiated and the callback function defined */
var myCallBackFunction = function () {alert("original");};
var MyClassInstance = new MyClass();
myCallBackFunction = MyClassInstance.modifyCallBack( myCallBackFunction );
myCallBackFunction();

Categories