Cross module function scope? Where is it looking - javascript

Given the following:
include.js
module.exports = function() {
...
return {
func: function(val) {
return Function('return ' + val + ';');
}
}
}()
running.js
var outer = function() {
var include = require('./include.js');
var x = include.func('eq');
console.log(x(5, 5));
}
outer()
...where would I put function eq(x, y){ return x === y; } such that this would work? I'm currently getting an eval at <anonymous> on the line that calls the function; x(5,5) in this case.
It doesn't like when eq is in include.js or when it's in running.js ~ I know this is example code is taken from my project and made pretty ambiguous...but, if it's possible, where would that function go?
OR
...would it be better to define an object of functions where the keys are the name of the function?
defaultFuncs = {
'eq': function(x, y){ return x === y; }
}

The parent scope of functions created via new Function is the global scope, not any local or module scope. So
global.eq = function(a,b) { return a==b };
function func(name) { return Function("return "+name+";"); }
var x = func("eq");
var equals = x();
equals(5, 5) // true
should work.
...would it be better to define an object of functions where the keys are the name of the function?
Definitely yes.

Related

Module pattern - separation of concerns - encapsulation in ES6

I am about to rewrite an app (it is in vanilla JS originally) in ES6, in which module patter is apllied.
In no time, at the beginning I realized that I am struggling to get 'separation of concerns' done since if we are about to apply data privacy in ES6 we only use "{}" but not IIFE's as in case of vanilla JS (which as known are practically function expressions).
Vanilla JS solution:
var budgetController = (function() {
const x = 20;
function add(a) {
return x + a;
}
return {
getSum: function(b){
console.log(add(b));
}
}
})();
UIController = (function() {
// some code
})();
Controller = (function(BudgetCrtl, UICtrl) {
var n = BudgetCrtl.getSum(3);
console.log(n);
})(budgetController, UIController);
In ES6 I attemted to use simply func expressions not IIFE's in order to pass the other modul in the controller modul and be able to use/pass over the public methods but it dod not work.
ES6 attempt:
let budgetController = function() {
const x = 20;
function add(a) {
return x + a;
}
return {
getSum: (b) => console.log(add(b))
}
}
UIController = function() {
// some code
}
Controller = function(BudgetCrtl, UICtrl) {
const n = BudgetCrtl.getSum();
console.log(n);
}
Controller(budgetController, UIController);
Could anyone provide me with some solution to involve somehow in ES6 the so called encapsulation and above mentioned things? Any idea would be appreciated!
Cheers, thank you!
You need to execute that BudgetCrtl to get access to the getSum function like so BudgetCrtl().getSum(3), since that BudgetCrtl is a function and not
a value returned from it's execution .
plus if you want the value to be stored to the n you should not console.log in the arrow function immediately, because the way it is now it's implicitly returning undefined
let budgetController = function() {
const x = 20;
function add(a) {
return x + a;
}
return {
getSum: (b) => {
let newVal = add(b)
console.log(newVal)
return newVal // so that you can store the value in `n`
}
}
}
UIController = function() {
// some code
}
Controller = function(BudgetCrtl, UICtrl) {
const n = BudgetCrtl().getSum(3);
console.log(n);
}
Controller(budgetController, UIController);

Will it be any difference whether I declare f as global variable or local variable in Javascript?

function functionFunction(str) {
var f;
return f=function(obj){
return str+', '+obj;
}
}
functionFunction('Hello')('world')
Here is my code. The function functionFunction will return function f. When I declared variable f in the function functionFunction, the output is" Hello, World". When I declared the variable outside the function functionFunction, the output is the same.(Code as below). But I know in Javascript the global and local variable works on different scope. However, in this case, whether the variable f is global or is local, has no effect on the result. I wonder why
var f;
function functionFunction(str) {
return f=function(obj){
return str+', '+obj;
}
}
functionFunction('Hello')('world')
TL;DR: No, there is no functional difference.
When doing return f= function() you get a reference to the function and also set the variable f even though f is never actually used anywhere. Your code would work equally well without the variable as is not being used.
function functionFunction(str) {
return function(obj) {
return str + ', ' + obj;
}
}
let s = functionFunction('Hello')('world');
console.log(s);
You could also use ES6 syntax to do this too
const functionFunction = str => {
return obj => str + ', ' + obj
}
let s = functionFunction('Hello')('world');
console.log(s);

Get current function name in strict mode

I need the current function name as a string to log to our log facility. But arguments.callee.name only works in loose mode. How to get the function name under "use strict"?
For logging/debugging purposes, you can create a new Error object in the logger and inspect its .stack property, e.g.
function logIt(message) {
var stack = new Error().stack,
caller = stack.split('\n')[2].trim();
console.log(caller + ":" + message);
}
function a(b) {
b()
}
a(function xyz() {
logIt('hello');
});
You can bind function as its context then you can access its name via this.nameproperty:
function x(){
console.log(this.name);
}
x.bind(x)();
After little research here is a good solution :
function getFnName(fn) {
var f = typeof fn == 'function';
var s = f && ((fn.name && ['', fn.name]) || fn.toString().match(/function ([^\(]+)/));
return (!f && 'not a function') || (s && s[1] || 'anonymous');
}
function test(){
console.log(getFnName(this));
}
test = test.bind(test);
test(); // 'test'
Source : https://gist.github.com/dfkaye/6384439
Building on #georg solution, this one returns just the function name. Note though that it may fail if called from an anonymous function
function getFncName() {
const stackLine = (new Error())!.stack!.split('\n')[2].trim()
const fncName = stackLine.match(/at Object.([^ ]+)/)?.[1]
return fncName
}
function Foo() {
console.log(getFncName()) // prints 'Foo'
}
A simple solution to dynamically retrieve function names [like magic variables] is the use of scoped variables, and the Function.name property.
{
function foo() {
alert (a.name);
}; let a = foo
}
{
function foo2() {
alert(a.name)
}; let a = foo2
};
foo();//logs foo
foo2();//logs foo2
Note: Nested functions cease to be source elements, and are hence not hoisted. Also, this technique cannot work with anonymous functions.
If (like me) you want to define this elsewhere and call it generically, you can store the code as a string somewhere global or import it, then eval() it wherever to access the current function name. (Using eval keeps the context at the point of invocation.)
There's gotta be a way to do this without using a string, but whatever.
SomeObject.whatFunc =
'const s = new Error().stack;' +
"const stackLine = new Error().stack.split('\\n')[2].trim();" +
'const fncName = stackLine.match(/(?<=at )(.*)(?= \\()/gm)[0];' +
'console.log(fncName);'
// Whereever you want the func name
function countBananas('weeee') {
eval(SomeObject.whatFunc)
// blah blah blah
}
countBananas() // logs 'countBananas'
just an update to get the full name :
function logIt(message) {
var stack = new Error().stack,
// update is on this line
caller = stack.split('\n')[2].trim().split(/\s+/)[1];
console.log(caller.trim().split(/\s+/)[1];);
}
function a(b) {
b()
}
a(function xyz() {
logIt('hello');
});

Javascript - need explanation on the variable inside IIFE

I have this code - I just wonder why after I add 'var' to foo variable, it doesn't work (it shows me foo is undefined)... Can anyone help explain these two functions? Thanks!
window.onload = function() {
var test = foo().steps(2);
console.log(test);
}
(function() {
//if I remove var, then it prints out a function which is what I expected
var foo = function() {
var steps = 1;
function callMe(g) {
//do something else
console.log("hello" + g);
}
callMe.steps = function(x) {
//if no arguments then return the default value
if (!arguments.length) return steps;
console.log(arguments);
//otherwise assign the new value and attached the value to callMe
steps = x;
return callMe;
}
return callMe;
}
})();
adding var to foo makes foo a local variable inside the IIFE and thus you can't access it outside.

JavaScript pass scope to another function

Is it possible to somehow pass the scope of a function to another?
For example,
function a(){
var x = 5;
var obj = {..};
b(<my-scope>);
}
function b(){
//access x or obj....
}
I would rather access the variables directly, i.e., not using anything like this.a or this.obj, but just use x or obj directly.
The only way to truly get access to function a's private scope is to declare b inside of a so it forms a closure that allows implicit access to a's variables.
Here are some options for you.
Direct Access
Declare b inside of a.
function a() {
var x = 5,
obj = {};
function b(){
// access x or obj...
}
b();
}
a();
If you don't want b inside of a, then you could have them both inside a larger container scope:
function container() {
var x, obj;
function a(){
x = 5;
obj = {..};
b();
}
function b(){
// access x or obj...
}
}
container.a();
These are the only ways you're going to be able to use a's variables directly in b without some extra code to move things around. If you are content with a little bit of "help" and/or indirection, here are a few more ideas.
Indirect Access
You can just pass the variables as parameters, but won't have write access except to properties of objects:
function a() {
var x = 5,
obj = {};
b(x, obj);
}
function b(x, obj){
// access x or obj...
// changing x here won't change x in a, but you can modify properties of obj
}
a();
As a variation on this you could get write access by passing updated values back to a like so:
// in a:
var ret = b(x, obj);
x = ret.x;
obj = ret.obj;
// in b:
return {x : x, obj : obj};
You could pass b an object with getters and setters that can access a's private variables:
function a(){
var x = 5,
obj = {..},
translator = {
getX : function() {return x;},
setX : function(value) {x = value;},
getObj : function() {return obj;},
setObj : function(value) {obj = value;}
};
b(translator);
}
function b(t){
var x = t.getX(),
obj = t.getObj();
// use x or obj...
t.setX(x);
t.setObj(obj);
// or you can just directly modify obj's properties:
obj.key = value;
}
a();
The getters and setters could be public, assigned to the this object of a, but this way they are only accessible if explicitly given out from within a.
And you could put your variables in an object and pass the object around:
function a(){
var v = {
x : 5,
obj : {}
};
b(v);
}
function b(v){
// access v.x or v.obj...
// or set new local x and obj variables to these and use them.
}
a();
As a variation you can construct the object at call time instead:
function a(){
var x = 5,
obj = {};
b({x : x, obj: obj});
}
function b(v){
// access v.x or v.obj...
// or set new local x and obj variables to these and use them.
}
a();
Scope is created by functions, and a scope stays with a function, so the closest thing to what you're asking will be to pass a function out of a() to b(), and that function will continue to have access to the scoped variables from a().
function a(){
var x = 5;
var obj = {..};
b(function() { /* this can access var x and var obj */ });
}
function b( fn ){
fn(); // the function passed still has access to the variables from a()
}
While b() doesn't have direct access to the variables that the function passed does, data types where a reference is passed, like an Object, can be accessed if the function passed returns that object.
function a(){
var x = 5;
var obj = {..};
b(function() { x++; return obj; });
}
function b( fn ){
var obj = fn();
obj.some_prop = 'some value'; // This new property will be updated in the
// same obj referenced in a()
}
what about using bind
function funcA(param) {
var bscoped = funcB.bind(this);
bscoped(param1,param2...)
}
No.
You're accessing the local scope object. The [[Context]].
You cannot publicly access it.
Now since it's node.js you should be able to write a C++ plugin that gives you access to the [[Context]] object. I highly recommend against this as it brings proprietary extensions to the JavaScript language.
You can't "pass the scope"... not that I know of.
You can pass the object that the function is referring to by using apply or call and send the current object (this) as the first parameter instead of just calling the function:
function b(){
alert(this.x);
}
function a(){
this.x = 2;
b.call(this);
}
The only way for a function to access a certain scope is to be declared in that scope.
Kind'a tricky.
That would lead to something like :
function a(){
var x = 1;
function b(){
alert(x);
}
}
But that would kind of defeat the purpose.
As others have said, you cannot pass scope like that. You can however scope variables properly using self executing anonymous functions (or immediately executing if you're pedantic):
(function(){
var x = 5;
var obj = {x:x};
module.a = function(){
module.b();
};
module.b = function(){
alert(obj.x);
};
}());
a();
I think the simplest thing you can do is pass variables from one scope to a function outside that scope. If you pass by reference (like Objects), b has 'access' to it (see obj.someprop in the following):
function a(){
var x = 5;
var obj = {someprop : 1};
b(x, obj);
alert(x); => 5
alert(obj.someprop); //=> 'otherval'
}
function b(aa,obj){
x += 1; //won't affect x in function a, because x is passed by value
obj.someprop = 'otherval'; //change obj in function a, is passed by reference
}
You can really only do this with eval. The following will give function b function a's scope
function a(){
var x = 5;
var obj = {x};
eval('('+b.toString()+'())');
}
function b(){
//access x or obj....
console.log(x);
}
a(); //5
function a(){
this.x = 5;
this.obj = {..};
var self = this;
b(self);
}
function b(scope){
//access x or obj....
}
function a(){
var x = 5;
var obj = {..};
var b = function()
{
document.println(x);
}
b.call();
}
Have you tried something like this:
function a(){
var x = 5;
var obj = {..};
b(this);
}
function b(fnA){
//access x or obj....
fnA.obj = 6;
}
If you can stand function B as a method function A then do this:
function a(){
var x = 5;
var obj = {..};
b(this);
this.b = function (){
// "this" keyword is still === function a
}
}

Categories