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
}
Related
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();
}
I am trying to understand closures. In the code below, I create an instance of the constructor function Ninja and I call the instance kawazaki. I expected to be able to access the methods of Ninja. However, I am getting a TypeError: Object #<Ninja> has no method 'feints' instead.
The output I expected was 1.
Here is my code:
function Ninja() {
var feints = 0;
function getFeints() {
return feints;
}
function feints() {
feints++;
}
}
var kawazaki = new Ninja();
kawazaki.feints();
console.log(kawazaki.getFeints());
Try this instead:
var kawazaki = new Ninja;
kawazaki.feints();
alert(kawazaki.getFeints());
function Ninja() {
var feints = 0;
this.getFeints = function () {
return feints;
};
this.feints = function () {
feints++;
};
}
You need to assing public properties to this within the constructor function.
The scope of the functions getFeints and feints is limited to the function Nija. As you can not access to variables declared in a function, you can not access to those functions.
To be able to execute kawazaki.feints(), you have to "attach" the function to the Ninja function, as an object (which a function also is)
You will find in these resources several ways to achieve that, and also some deeper explanations:
How do JavaScript closures work?
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Inheritance_and_the_prototype_chain
Closure is a very simple yet largely misunderstood topic.
function Ninja() {
var feints = 0;
function getFeints() {
return feints;
}
function feintsInc() {
feints++;
}
}
You have defined the closure alright but please note that a closure is not actually a method of the object. In order to get your desired output you need to call the closures just before closing the object.
feintsInc();
getFeints();
If,however, you wish to do it as
kawazaki.feintsInc();
you need to use this keywords in your function to get the functions assigned to the object.
Note,make sure your functions and variable names don't overlap.
This question already has answers here:
How can I access local scope dynamically in javascript?
(4 answers)
Closed 9 years ago.
Does JavaScript have a variable for items declared in the function's scope? I would like to access items declared inside a function using an associative array.
For example I can do the following with items at the global scope
var globalVar = "hi";
var myFunction = function () {
alert(window["globalVar"]);
};
But I would like to do a similar thing with variables declared inside a function
var myFunction = function () {
var funcVar = "hi";
alert(func["funcVar"]);
};
I realise doing such a thing isn't necessarily a good thing and I am doing the below instead, but I am still interested if JavaScript has such a variable.
var myFunction = function () {
var func = {funcVar : "hi" };
alert(func["funcVar"]);
};
This question has been asked and answered many times. No, in JavaScript there is no local object containing local variables as properties (in the way that for instance, in browser environments the window object contains global variables as properties).
Depending on what you are trying to accomplish, there are probably many alternative ways to attack it, including the one you are using now.
Duplicate of Javascript: Get access to local variable or variable in closure by its name, How can I access local scope dynamically in javascript?, Javascript local variable declare.
Perhaps you could assign properties to the function object itself, and reference those?
var myFunction = function() {
myFunction.funcVar = 'hi';
alert(myFunction['funcVar']);
};
It is not exactly the answer to your question, but it's the best way I can think of to access local variables as properties of an object. Note that in this method these variables will be visible outside the function in the same manner (that is, looking up the properties of the function).
If you really needed those properties to be hidden, you could hide them within a closure, like so:
var myFunction = function() {
(function hidden() {
hidden.funcVar = 'hi';
alert(hidden['funcVar']);
})();
};
Functions are just special objects that can be invoked. You can set properties of a function, and get them later.
var a = function () {
alert(a.testingVar);
};
a.testingVar = "asdf";
a();
DEMO: http://jsfiddle.net/gEM7W/
Although I don't see a reason/need to do this. You could always use a closure to keep local variables specific to a function. For example:
var a = (function () {
var obj = {
testingVar: "asdf"
};
return function () {
alert(obj.testingVar);
};
})();
a();
DEMO: http://jsfiddle.net/gEM7W/1/
You don't really have associative arrays. You have indexed arrays and you have objects.
In the future, there will be an iterator which will happily traverse both, without any side-effects. At that point, perhaps people will forget the difference.
However, the properties still wouldn't be order-based:
$arr = array(0, 1, "name"=>"Bob", 3);
In another language might get you an array where the keys are: 0, 1, "name", 3
In JS, you'd get 0, 1, 2, "name" (or "name", 0, 1, 2).
So stick with indexed arrays and objects with properties.
That said, you've got multiple options.
var myFunc = function () {
var private_data = {
name : "Bob",
age : 32
};
return {
getName : function () { return private_data.name; /* or private_data["name"] if that's really what your heart longs for */ },
get : function (key) { return private_data[key] || null; },
set : function (key, val) { private_data[key] = val; }
};
};
Now everything is private, and you can access them by property-name, using dot or bracket notation.
If they can be public, and the function is always going to be called the same thing (ie: not a constructor making an instance) then you can attach yourself to the actual function:
var myFunc = function () {
myFunc.name = "Bob";
myFunc["age"] = 32;
return {
get : function (key) { return (myFunc.hasOwnProperty(key)) ? myFunc[key] : null; }
};
};
Downside (or upside) is that myFunc is the public name. As such, these properties are publicly accessible.
Going the first route, you don't even need to declare a variable. You can just use the object you pass into a function.
var myFunc = function (dataObj) {
return {
getName : function () { return dataObj.name; },
setAge : function (val) { dataObj["age"] = val; }
};
};
var bob = myFunc({ name : "Bob" });
bob.setAge(32);
Now everything's private and I didn't even have to declare anything.
Closure keeps the object in play as long as there's a publicly accessible function that's returned, which still has access to that particular instance of the function call.
Once you figure out closures, this becomes a non-issue.
My code is very simple. Ans to me it should work.
var preview = WinJS.Class.define(
function (el, options) {
el.winControl = this;
this.el = el;
this.textarea = d.getElementById('preview-input');
this.preview = d.getElementById('preview-text');
this.form = d.getElementById('perview-form');
this.preview.addEventListener('click', this.click, false);
//WinJS.Utilities.query("button", this.form)
//this.preview.addEventListener('', this.save, false);
},
{
click: function (e) {
this.form.style('display', 'block');
}
}
);
WinJS.Namespace.define('RegCtrl', { preview: preview });
But when click occurs this.form seems to be undefined of null. Why? I do not want to initialize objects in every method of the class.
New tests
I made additional test very small
var preview = WinJS.Class.define(
function (el, options) {
var test = 1;
this.test = 1;
this.test1();
},
{
test1: function () {
console.log(this.form, test);
}
}
);
WinJS.Namespace.define('RegCtrl', { preview: preview });
This test fails on line this.test1();. What I think now that this class is called RegCtrl.preview() rather than new RegCtrl.preview().
How do I shek inside the function that this called as new but not a simple function?
The other answers aren't explaining what's going on, and as such are giving incorrect advice.
JavaScript has first-class function objects - you can pass them around as values. That's exactly what you're doing when you set up this callback:
this.preview.addEventListener('click', this.click, false);
You're taking the contents of the this.click property, which happens to be a function, and handing it to the addEventListener function to do whatever it wants with it.
I was very specific about terminology there - note I specifically said function, not method. JavaScript doesn't really have a method construct, it just has methods as properties on an object.
So where does the "this" member come from? It's determined at the caller - the object you use on the left side of the '.' is the one that becomes the value of this. For example,
function exampleFunc() { console.log("this.myName = " + this.myName); }
var a = { myName: "Chris", doSomething: exampleFunc };
var b = { myName: "Bob", doSomething: exampleFunc };
Note I've assigned the exact same function to the doSomething properties. What what happens:
a.doSomething(); // Outputs "this.myName = Chris"
b.doSomething(); // Outputs "this.myName = Bob"
The exact same function object, called through two different objects, has a different this pointer.
exampleFunc is a global function, let's call it:
exampleFunc() // Outputs "this.myName = undefined"
So where'd the undefined come from? In a global function, "this" is set to window (the global scope), which didn't have the myName property defined. Which also means that you could do this instead:
myName = "Global Name"; // note, no var - we want this global
exampleFunc(); // Outputs "this.myName = Global Name"
Ok, so what's going on with the original question? Basically, you've passed the function this.click to be the callback, but you haven't passed the "this" pointer that you want it called through. Actually, addEventListener doesn't have a way to pass the this pointer. As a result, when the function is invoked this is not pointing at your object. I don't remember off the top of my head what it's pointing at - it's either window or the element that was clicked on, check the DOM documentation to verify.
To get it to call the right function with the right context (context = the correct "this"), the traditional approach is to use a closure. Capture "this" in a variable, then pass in an anonymous function that calls your actual callback with the right this pointer. The code looks like this:
var preview = WinJS.Class.define(
function (el, options) {
// Capture your current this pointer in a global variable
// Using "that" as the name comes from JavaScript: The Good Parts book
var that = this;
el.winControl = this;
this.el = el;
this.textarea = d.getElementById('preview-input');
this.preview = d.getElementById('preview-text');
this.form = d.getElementById('perview-form');
// Note what gets passed instead of this.click:
this.preview.addEventListener('click',
function (e) {
// NOTE: Calling through "that": "this" isn't pointing to the right object anymore
// Calling through "that" resets "this" inside the call to click
that.click(e);
}, false);
},
{
click: function (e) {
this.form.style('display', 'block');
}
}
);
This is a common enough pattern that ECMAScript 5 has a utility function to build these wrappers for you - function.bind. Do this:
this.preview.addEventListener('click',
this.click.bind(this),
false);
The construct this.click.bind(this) will construct a new function that, when called, will set the "this" reference to whatever you passed (in this case "this"), and then invoke the function you called it on.
Yes, there are a lot of different values for "this" floating around. Keeping track of what "this" is pointing at is an important part of mastering JavaScript programming.
I think you may want to define a global JavaScript variable as :
var myForm = document.getElementById('perview-form');
or jest define var myForm; and initialize inside function (el, options) as:
myForm = d.getElementById('perview-form');
Now you can use this variable in your function as :
myForm.style('display', 'block');
EDIT: I believe you may define this variable as first line in your WinJS.Class.define to make it instance level variable as below:
var preview = WinJS.Class.define(
var myForm;
function (el, options) {
....
....
myForm = d.getElementById('perview-form');
...
},
{
click: function (e) {
myForm.style('display', 'block');
}
});
This is a really hard thing to research if you don't know what to look for. I added one line and changed another line. That should fix your issue.
In short, the keyword this gets reset every time you enter a new function, this the value of this inside your click function is not the same this of the outer scope. Preserve this this you want. The name of that seems fairly common.
Edited based on the link provided by the OP.
This code is UNTESTED. If using this doesn't work now, then I'd try this2
Sorry I can't test this, but I don't have the framework anywhere so I'm doing
educated guesswork.
var preview = WinJS.Class.define(
function (el, options) {
that = this; // No var should be needed since it is declared already
el.winControl = this;
this.el = el;
this.textarea = d.getElementById('preview-input');
this.preview = d.getElementById('preview-text');
this.form = d.getElementById('perview-form');
this.preview.addEventListener('click', this.click, false);
//WinJS.Utilities.query("button", this.form)
//this.preview.addEventListener('', this.save, false);
},
// This is the section for instance vars
{
click: function (e) {
that.form.style('display', 'block'); // AND THIS ONE
},
that: null // Added instance variable
},
// And these are static variables
{
that2: null
}
);
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