Is it possible inside list to get all available functions - a, b, c without their enumeration and without using window?
(function(){
function a() { return 1; }
function b() { return 2; }
function c() { return 3; }
function list()
{
return [a, b, c];
}
})();
No, it's not possible with functions declared directly in the current scope.
To achieve this, you would have to assign the functions to some property of the scope, i.e.:
(function() {
let funcs = {};
funcs.a = function() {
return 1;
}
...
function list() {
return Object.values(funcs);
}
});
NB: Object.values is ES7, in ES6 use:
return Object.keys(funcs).map(k => funcs[k]);
or in ES2015 or earlier use:
return Object.keys(funcs).map(function(k) { return funcs[k] });
If you haven't even got Object.keys, give up... ;)
I understand where you are trying to get. So perhaps this is the closest thing to what you requested, without using the window name (the same object though):
// define a non-anonymous function in the global scope
// this function contains all the functions you need to enumerate
function non_anon() {
function a() { return 1; }
function b() { return 2; }
function c() { return 3; }
function list() { return [a, b, c]; }
// you need to return your `list` function
// i.e. the one that aggregates all the functions in this scope
return list;
}
// since in here the purpose is to access the global object,
// instead of using the `window` name, you may use `this`
for (var gobj in this) {
// from the global scope print only the objects that matter to you
switch (gobj) {
case 'non_anon':
console.info(gobj, typeof this.gobj);
console.log(
// since you need to execute the function you just found
// together with the function returned by its scope (in order to `list`)
// concatenate its name to a double pair of `()` and...
eval(gobj + '()()') // evil wins
);
break;
}
}
Related
This seems to correctly return the correct value of 1:
let test = function() {
let test = 1;
function getTest() {
return test;
}
return {getTest};
}();
console.log(test.getTest());
But this does not:
let test = function() {
this.test = 1;
function getTest() {
return this.test;
}
return {getTest};
}();
console.log(test.getTest());
Why?
I am unsure what exactly you were trying to achieve with your code. An IIFE should not be mixed up with an object instantiation which I have demonstrated below. In this context the this works as expected:
const test=new function() { // object instantiation
this.test = 1; // this defines the property test
this.getTest=function(){
return this.test; // this references the same property
}
};
// test.test=123; // you can manipulate the property test here
console.log(test.getTest());
Or, in form of a simple object assignment:
const test={ // object assignment
test: 1, // defines the property `test`
getTest(){ return this.test; } // the `this` references the `test` property
};
console.log(test.getTest());
Because of the scope of this.
let test = function() {
this.test = 1; // this refers to the scope of the 1st level function
function getTest() {
return this.test; // this refers to the getTest function, and is undefined
}
return {getTest};
}();
console.log(test.getTest());
Just to make the point of the behavior of this you could use an arrow function, which captures the encompassing scope, including this
let test = function() {
this.test = 1;
const getTest = ()=> this.test; // still points to upper function
return {getTest};
}();
console.log(test.getTest());
But note that this a bad practice in this case because you keep in memory a reference to a function after it has reach end of scope. You shouldn't return any reference to this from a this kind of immediately invoked function, it creates a memory leak.
So a better thing to do would be to define the function and the test value on the returned object, with this being a reference to this object an not of a closure's scope object that doesn't exist any more
let test = function() {
return {
test: 1,
getTest() {
return this.test;
},
}
}();
console.log(test.getTest());
I'm currently working on some exercises to get a deeper understanding of the 'this' keyword. It does seem to have a lot of use cases so I did read on MDN about 'this'. I'm wondering, what does the 'this' keyword in this exercise refer to? I know that when you use apply (which has a maximum of 2 arguments), your first argument is where you want the this 'keyword to be referenced to' and the second argument is an array to which the 'this' keyword is newly referenced to. where is return fn.apply(this,arguments); being referenced to and what is arguments in the second argument? Is it in the function, the window? Sorry, I'm just really confused and trying to wrap my head around it. This is the line of code that I'm confused about:
function add(a, b) {
return a + b;
}
function invokeMax(fn, num) {
var counter = 0;
return function() {
counter++;
if (counter > num) {
return 'Maxed Out!';
}
return fn.apply(this, arguments);
};
}
You can console.log() this in the returned function and find out. Here, you will see it points to the global object (or window in a browser). This code doesn't depend on this being anything in particular. You could rewrite it as:
return fn.apply(null, arguments);
and get the same result.
this is determined by the way functions are called. The function here returns a function that (presumably) you will just call by itself, so the only calling's context is the window:
function add(a, b) {
return a + b;
}
function invokeMax(fn, num) {
var counter = 0;
return function() {
counter++;
if (counter > num) {
return 'Maxed Out!';
}
console.log("this is window?", this === window)
return fn.apply(this, arguments);
};
}
let f = invokeMax(add, 2)
console.log(f(5, 6))
Calling the same function in a different context leads to a different value of this:
function add(a, b) {
return a + b;
}
function invokeMax(fn, num) {
var counter = 0;
return function() {
counter++;
if (counter > num) {
return 'Maxed Out!';
}
console.log("this: ", this)
return fn.apply(this, arguments);
};
}
let someObj = {name: "myObj"}
someObj.f = invokeMax(add, 2) // now this will be someObj
someObj.f()
EDIT based on comment
A basic apply() example. The function will use the object passed to the first parameter of apply() as this in the function:
function print(someArg){
console.log(this.myName, someArg)
}
print.apply({myName: "Mark"}, ["hello"]) // set this to the passed in object
print.apply({myName: "Teddy"}, ["hello"]) // set this to the passed in object
print("hello") // called normally `this` will be the widow which doesn't have a `myName` prop.
// but you can give window that property (but probably shouldn't)
window.myName = "I'm window"
print("hello")
In that instance this refers to the current scope, which is the function where this is contained. In JavaScript, functions are also objects that can have properties assigned to them.
In the code below there is callback function used with forEach loop going over returned results. Is variable 'error' inside forEach loop and 'error' in callback same variables ?
session.getAll(options, function (error, varbinds) {
varbinds.forEach(function (vb) {
if (error)
console.log('getALL Fail ');
else
console.log(vb.value);
});
});
Yes, it is the same variable.
I'm not sure how much you know. So, I'm going to explain in detail. Scoping in JavaScript is at the function level*. Think of function definitions as points on a tree. Each point on the tree is a scope. When using a variable, you can only use what is at your current scope and anything available to ancestors going up to the top (global scope). Here are a few rules & examples that may help you better understand:
*UPDATE: ES6 const and let are block-level
Inner functions have access to outer function-level variables
function a() {
var a = 4;
function b() {
alert(a); /* a = 4 */
}
}
Parameters are defined at the same scope as if they were defined one line below
function a(a) {
// variable "a" is at same scope as the example above
function b() {
alert(a);
}
}
Variables in adjacent functions are not accessible
Function a() is the parent. b() and c() are its children. Those children cannot access each other's variables.
function a() {
function b() {
var aValue = 2;
}
function c() {
alert(aValue); /* "aValue" is undefined here */
}
}
Location of function definition is what counts
This returns 5 if you run main();:
function getValue(returnFunc) {
var a = 7;
alert(returnFunc());
}
function main() {
var a = 5;
getValue(function() { return a; }); // anonymous function becomes "returnFunc"
}
Lastly, variable overriding
(function getValue() {
var a = 5;
(function () {
var a = 7;
alert(a);
})();
alert(a);
})();
I tried to avoid using self-invoking functions/IIFEs for these examples but I just couldn't help myself on this last one. It's the easiest way, I think. Run this and you'll get 7, then 5. But, if you exclude "var" on that inner "a"...
(function getValue() {
var a = 5;
(function () {
a = 7;
alert(a);
})();
alert(a);
})();
You'll get 7, 7. This is because "var" creates a new space in memory. Also, if there is a name conflict with something in a higher scope, it gets overridden as a different variable (despite having the same name).
For some more examples, please see: What is the scope of variables in JavaScript?
Yes, it's the same variable, it would change if you define another error variable inside the scope of the forEach callback by using the var keyword:
session.getAll(options, function (error, varbinds) {
varbinds.forEach(function (vb) {
if (error) //Same error as the error parameter above
console.log('getALL Fail ');
else
console.log(vb.value);
});
});
session.getAll(options, function (error, varbinds) {
varbinds.forEach(function (vb) {
var error = false; //New error for this closure.
if (error)
console.log('getALL Fail ');
else
console.log(vb.value);
});
});
I want a main object M containing a sub-object S which has some method E which has a private variable P. I also want the method E to have access to M via another variable V. For the private variables I'm doing this:
M.S = function () {
var P,
V; // how to set V to M?
return {
E: function () {
// stuff goes here
}
}
}();
One solution I came up with was to remove the () at the last line, and then calling the anonymous S-creating function as a method of M. this solves the problem, but I'm thinking there might be a more elegant way to go about it.
M.S = function () {
var P,
V = this;
return {
E: function () {
// stuff goes here
}
}
};
M.S = M.S()
Mostly I need to know what is good practice for this, since I'm new to private variables in Javascript.
A pretty straightforward method to do this is:
M.S = function (V) { // <-- V is declared locally
var P;
return {
E: function () {
// stuff goes here
}
};
}(M);
V is locally declared through the formal parameter. M's reference is assigned to V, through function(V){...}(M);.
Even when M is redeclared at a later point, V will still point to the right object.
What about this? You invoke S in context of M:
M.S = function () {
var P,
V = this; // how to set V to M?
return {
E: function () {
// stuff goes here
// you can refer M via V reference
}
}
}.call(M);
I understand calling function(1) but not function(1)(2), how does it work?
also possible for function(1)(2)(3)(4) too?
In this case you are supposing that function(1) returns a function, than you are calling this new, anonymous function with an argument of 2.
See this example:
function sum(a) {
return function(b) {
return a+b;
}
}
// Usage:
window.alert(sum(5)(3)); // shows 8
var add2 = sum(2);
window.alert(add2(5)); // shows 7
window.alert(typeof(add2)); // shows 'function'
Here we create a function sum that takes one argument. Inside the function sum, we create an anonymous function that takes another argument. This anonymous function is returned as the result of executing sum.
Note that this anonymous function is a great example of what we call closure. A closure is a function that keeps the context in which it was created. In this case, it will keep the value of the variable a inside it, as did the example function add2. If we create many closures, they are independent as you can see:
var add3 = sum(3);
var add4 = sum(4);
window.alert(add3(3)); // shows 6
window.alert(add4(3)); // shows 7
Furthermore, they won't get "confused" if you have similarly named local variables:
var a = "Hello, world";
function multiply(a) {
return function(b) {
return a * b;
}
}
window.alert(multiply(6)(7)); // shows 42
var twoTimes = multiply(2);
window.alert(typeof(twoTimes));
window.alert(twoTimes(5));
So, after a call to sum(2) or multiply(2) the result is not a number, nor a string, but is a function. This is a characteristic of functional languages -- languages in which functions can be passed as parameters and returned as results of other functions.
You have a function that returns a function:
function f(n) {
return function(x) {
return n + x;
};
}
When you call f(1) you get a reference to a function back. You can either store the reference in a variable and call it:
var fx = f(1);
var result = fx(2);
Or you can call it directly:
var result = f(1)(2);
To get a function that returns a function that returns a function that returns a function, you just have to repeat the process:
function f(n) {
return function(x) {
return function(y) {
return function(z) {
return n + x + y + z;
}
}
};
}
If your function returns a function, you can call that too.
x = f(1)(2)
is equivalent to:
f2 = f(1)
x = f2(2)
The parenthesis indicate invocation of a function (you "call" it). If you have
<anything>()
It means that the value of anything is a callable value. Imagine the following function:
function add(n1) {
return function add_second(n2) {
return n1+n2
}
}
You can then invoke it as add(1)(2) which would equal 3. You can naturally extend this as much as you want.