I wrote a program like this:
function a(x,y,z) {
function b(foo,bar) {};
function c(foo,bar) {};
function d(foo,bar) {};
function e(foo,bar) {};
function f(foo,bar) {};
}
I call the function this way:
for(var i=0; i<5; i++) { charts[i] = a(x[i],y[i],z[i])}
x,y and z are global arrays of length 5 and some properties.
Now, the loop gets executed before page load and all the functions for each of the array is also executed as expected (There are event listeners bound to elements in these functions)
Let's say I want to access some local variables from b,c,d,e or f "after" page load, when an event is invoked, how do i do it? I'm talking about "scope" here I think.
Do I have to make the whole thing an object?
Also, there are local variables inside b,c,e and f (locally declared and not using "this").
There are also variables inside of a which is accessed by b,c,d,e and f (Again, locally declared, not using "this")
Thanks!
You can simple create a new object inside a and return that object.
var a = function (x, y, z) {
var result = {};
var outerVal = x;
result.b = function (foo, bar) { return foo + bar; };
result.c = function (foo, bar) { return outerVal + result.g + z}; //closure
result.d = function (foo, bar) { };
result.e = function (foo, bar) { };
result.f = function (foo, bar) { };
result.g = y;
//If you want to execute the functions you can do so
result.bValue = result.b(x, y);
result.c(y, z);
return result;
};
var anA = a(1, 2, 3);
console.log(anA.bValue); //3
console.log(anA.b(2, 5)); //7
console.log(anA.c()); //6
What Amberlamps said, you cannot access local variables from outside of the scope they are created, meaning your function a cannot "see" any variables created in b, c, d, e, f. You could either create some global variables (global to b, c, d, e and f) or you could consider writing a closure:
var something = (function () {
var globalOne = null,
globalTwo = null;
//...
return {
a: function (x, y, z) {
something.b(foo, bar);
something.c(foo, bar);
},
b: function (foo, bar) {
},
c: function (foo, bar) {
}
// etc.
};
}());
This could be a little overkill for what you're trying to do, but what's nice with the closure is that your globals globalOne and globalTwo cannot be modified by the client.
Related
I wonder if there's a way to define a varibles to a function local [[Scopes]] for example the following function
//Parent function has a global scope {Window}
function x() {
//Local variable, closure to function {x}
var a = 123;
//Local function which have access to all {x} local scope like {a}
function y() {
console.log(a)
}
//Check the function y scope {window, Closure(x){a=123}
console.dir(y)
}
x()
the function above Scopes should to be like that
0: Closure (x) {a: 123}
1: Global {window: Window, self: Window, document: docume...
which can access window object and it's parent closures like a
another example for a local function which has 3 Scopes when using eval()
//Parent function has a global scope {Window}
function s(obj, fn) {
//Local variable and closure to {s} function
var q = 123
if (typeof fn === 'function') {
/*
- {y} here is local function which before {eval} have 2 scope
- {window}, closure (s) {obj: {a: "a", b: "b", c: "c"}, q = 123}
- after using of eval it's will get a new scope {block} scope Which will allow this function to access everything like obj, fn, y itself, q everything inside the parent function not just a Closure scope for things used on it like {q} and also it's will change
* closure (s) {obj: {a: "a", b: "b", c: "c"}, q = 123}
- to
* closure (s) {arguments: Arguments(2) [{…}, ƒ, callee: ƒ, Symbol(Symbol.iterator): ƒ], fn: ƒ (), obj: {a: "a", b: "b", c: "c"}, q: 123, r: 989
- the new closure will add everything even if it's not used on {y}
*/
function y(a) {
console.log(obj.a, q)
}
//That's will add a new scope to function {y} and change closure scope of it
eval('var r = 989')
//check {y} scope
console.dir(y)
}
}
s({
'a': 'a',
'b': 'b',
'c': 'c'
}, function() {console.log('i am a global function')})
the function y above have access to x arguments, vatiables, blocks like y function the Scope the of function above will be like that
0: Block (s) {defVar: ƒ}
1: Closure (s) {obj: {…}, q: 123, arguments: Arguments(2), fn: ƒ, defVar: ƒ, …}
2: Global {window: Window, self: Window, document: docume...
but if i have the following functions
//global function
//scrope = {window}
function x(fn) {
var q = 123;
//here's i want to define q var a local scope of {fn}
//like fn['[[Scopes]]']['1'] = 'Closure (x) {q: 123}' so when calling q from {fn} it's will return the q value i want to define it with the same name not like argument
console.log(fn())
};
//global function
//scrope = {window}
//i want to allow var q of {x} function to be used inside this function normally like
//function(){var t = "i'am a global function"; return t, q }
//the example above will return Uncaught ReferenceError: q is not defined
x(function(){var t = "i'am a global function"; return t, q })
2 functions above will be in the global scope window so is there's a way to add new scope to function something like fn['[[Scopes]]']['1'] = 'Closure (x) {q: 123}' or fn['[[Scopes]]']['1'] = x['[[Scopes]]']['1'] i know that [[Scopes]] cannot be accessed as property but it's just example
another example
// i want to do here the same at comments in example above
function x(fn) {
var q = 123;
y()
};
function y(){return 'str'}
is there's a way to set a new closures to the function y from function x like y['[[Scopes]]']['1'] = {a = 123, b = 456}
all i want to do is to set a local varibles to a function from another one or allow a global function to access cloures of another function
the last example to be more clear
the following function select html elements with presented key, value
i want when use the optional function to access the variables declared in selectElements method or define it to the optional function
HTML
<nav>
<ul class="nav-items">
<li class="nav-active">Home</li>
<li class="nav-item">Fruits</li>
<li class="nav-item">Veggies</li>
</ul>
</nav>
function selectElements(obj, fn) {
var sel = {
'class': function(el, arg) {
if (arg) {
return document.getElementsByClassName(el)
} else {
return 'document.getElementsByClassName("'+el+'")'
}
},
'id': function(el, arg) {
if (arg) {
return document.getElementById(el)
} else {
return 'document.getElementById("'+el+'")'
}
},
'tag': function(el, arg) {
if (arg) {
return document.getElementsByTagName(el)
} else {
return 'document.getElementsByTagName("'+el+'")'
}
}
}
if (typeof fn === 'function') {
var closureHanlder, text = ''
//console.dir(fn, defVar)
for(var i in obj) {
obj[i].replace(/^\./, function(elem) {
elem = obj[i].replace(/^\./, '');
elem = sel.class(elem);
text += 'var ' + i + ' = ' + elem + ';\n'
}).replace(/^\#+/, function(elem) {
elem = obj[i].replace(/^\#/, '');
elem = sel.id(elem);
text += 'var ' + i + ' = ' + elem + ';\n'
}).replace(/^\w+/, function(elem) {
if (!elem.startsWith('undefined')) {
elem = sel.tag(elem)
text += 'var ' + i + ' = ' + elem + ';\n'
}
})
}
console.log(text)
//decalre the elements with variables name
eval(text)
console.log(nav, navActive, navItem, navContainer)
// i want this function to get the declared elements as local variables or access them from this function {selectElements}
fn()
}
}
var el = {
'nav': 'nav',
'navActive': '.nav-active',
'navItem': '.nav-item',
'navContainer': '.nav-items'
}
selectElements(el, function () {
//here i want to access those varibles
//console.log(nav, navActive, navItem, navContainer)
// as a local varibles or access them from the function wheich used on it
})
To the best of my knowledge you can't. For starters [[Scopes]] is not a standard internal slot of any function object nor is it of ANY object for that matter. So at best you would be looking at a solution for Chrome only and it most certainly wouldn't be available through javascript.
There's also very little to be gained here. The function wouldn't know about what other variables you are including into its scope. If you are hoping to add a scope that's constant then there's no point to it either since you could just add the respective declarations to the respective function.
This is why with failed to provide any real value while also making you question whether any identifier is also being shadowed by the new dynamic context.
(function foo() { var a=b=c=1 }())
When I try to log a will return a not defined err, however, when I try to log b or c will return the value 1. It's wicked.
b and c are added into the window object and get their values as 1. But a is declared via var. This means that a is visible only in the function context and not outside from it.
Your code is equivalent
(function foo() {
c = 1;
b = c;
var a = b;
}())
however, when I try to log b or c will return the value 1.
Because you didn't localized the scope (inside the function) of b and c by using var or let or const.
Without var, let or const, these variable will take the scope in which this function is defined.
If the outer scope (not outermost) also doesn't localize those variables, then parent scope is checked again till the outermost scope (window). And the variable gets added to outermost scope if no local scope is defined for them. for example
function a() {
(function foo() {
var a = b = c = 1;
}());
console.log(b, c); //print 1,1
}
a();
console.log(b, c); //print 1,1
However, if these variables are defined in outer scope, then they don't get added to the outermost (window) scope. For example, following will throw an error.
function a() {
var b,c;
(function foo() {
var a = b = c = 1;
}());
a();
console.log(b, c);
}
console.log(b, c);
If you have lots of constructs where you want to initialise to some constants and you can use ES6 features the following is a nice way to do it.
//store function in your lib
function* initVar(value) {
while (true) yield value;
}
//using function
let
[a,b,c] = initVar(0),
[d,e,f] = initVar("xyz"); //not just limited to numbers.
console.log(a,b,c,d,e,f);
In JavaScript, functions can have properties. Like this:
var f = function(){ console.log("Hello!"); }
f.x = "Whoohoo";
How do I retrieve x from code within f() that might be called long after the variable f goes out of scope?
You could use the property accessor, like the assignment.
var f = function() { console.log("Hello! " + f.x); }
f.x = "Whoohoo";
console.log(f.x);
f();
For stable access, you could use a named function
var f = function foo() { console.log("Hello! " + foo.x); }
// ^^^ >>>>>>>>>>>>>>>>>>>>>>>>>>> ^^^
f.x = "Whoohoo";
console.log(f.x);
f();
If you need some more robust (but also more verbose):
var f = (function(){
var func = () => {
console.log(func.a)
}
return func
})()
f.a = 'Whoohoo'
// trying to break it
var a = f
f = 'somethingelse'
a()
If what you're looking for is to simply access that property from within your function f, you simply reference the function object (either by the variable name if it's a function expression, or by the function name if it's a function declaration).
For example:
var f = function(){ return f.x; };
f.x = "Whoohoo";
// f() => "Whoohoo"
var b = function(){ return f.x; ];
// b() => "Whoohoo"
However, your mention of calling f "long after the variable f goes out of scope" contradicts the lexical scoping of JavaScript. You cannot call the function f unless you do so from the same scope where the function was defined, or from a child scope in reference to where the function was defined. If you are "out of scope", invoking f will throw a reference error.
Let's get a little convoluted. f is already the name of the function by the expression that defines it. And a function is an object by definition in JS. So you can access it and it's properties (such as x) through the f keyword like f.x. Yet, since f is a function, you may use the it as a constructor too and do silly things like...
var f = function(){ console.log("Hello!"); };
f.x = "Whoohoo";
f.prototype.thingy = function(){
console.log(this.constructor.x);
};
var a = new f();
a.thingy();
... and from this point on lets get a little more convoluted. You might event do;
function F(){
F.prototype.thingy = function(){
return this.constructor.x;
};
var obj = Object.create(F.prototype);
console.log("Hello!");
return obj.thingy();
}
F.x = "Whoohoo";
console.log(F());
So you can get the value of a property of the function object F "from within itself" by taking an object instantiated by itself under a closure.
JavaScript has lexical scoping which means that non-local variables accessed from within a function are resolved to variables present in the parents' scope of that function when it was defined. This is in contrast to dynamic scoping in which non-local variables accessed from within a function are resolved to variables present in the calling scope of that function when it is called.
x=1
function g () { echo $x ; x=2 ; }
function f () { local x=3 ; g ; }
f # does this print 1, or 3?
echo $x # does this print 1, or 2?
The above program prints 1 and then 2 in a lexically scoped language, and it prints 3 and then 1 in a dynamically scoped language. Since JavaScript is lexically scoped it will print 1 and then 2 as demonstrated below:
var print = x => console.log(x);
var x = 1;
function g() {
print(x);
x = 2;
}
function f() {
var x = 3;
g();
}
f(); // prints 1
print(x); // prints 2
Although JavaScript doesn't support dynamic scoping we can implement it using eval as follows:
var print = x => console.log(x);
var x = 1;
function g() {
print(x);
x = 2;
}
function f() {
// create a new local copy of `g` bound to the current scope
// explicitly assign it to a variable since functions can be unnamed
// place this code in the beginning of the function - manual hoisting
var g_ = eval("(" + String(g) + ")");
var x = 3;
g_();
}
f(); // prints 3
print(x); // prints 1
I would like to know if there exists another possible way to achieve the same result without resorting to eval.
Edit: This is what I'm trying to implement without using eval:
var print = x => console.log(x);
function Class(clazz) {
return function () {
var constructor;
var Constructor = eval("(" + String(clazz) + ")");
Constructor.apply(this, arguments);
constructor.apply(this, arguments);
};
}
var Rectangle = new Class(function () {
var width, height;
constructor = function (w, h) {
width = w;
height = h;
};
this.area = function () {
return width * height;
};
});
var rectangle = new Rectangle(2, 3);
print(rectangle.area());
I know that it's not a very good example but the general idea is to use dynamic scoping to create closures. I think this pattern has a lot of potential.
To add a note on this topic:
In JavaScript whenever you make use of:
function declaration statement or function definition expression then local variables will have Lexical Scoping.
Function constructor then local variables will refer to the global scope (top-level code)
this is the only built-in object in JavaScript that has a dynamic
scoping and is set through the execution (or invocation) context.
So to answer to your question, In JS the this is already dynamically scoped feature of the language and you even don't need to emulate another one.
Attribute lookup falls through the prototype chain, which matches quite well to dynamic scopes. Just pass your own environment of dynamically-scoped variables to use around instead of using Javascript's lexical scoping.
// Polyfill for older browsers. Newer ones already have Object.create.
if (!Object.create) {
// You don't need to understand this, but
Object.create = function(proto) {
// this constructor does nothing,
function cons() {}
// and we assign it a prototype,
cons.prototype = proto;
// so that the new object has the given proto without any side-effects.
return new cons();
};
}
// Define a new class
function dyn() {}
// with a method which returns a copy-on-write clone of the object.
dyn.prototype.cow = function() {
// An empty object is created with this object as its prototype. Javascript
// will follow the prototype chain to read an attribute, but set new values
// on the new object.
return Object.create(this);
}
// Given an environment, read x then write to it.
function g(env) {
console.log(env.x);
env.x = 2;
}
// Given an environment, write x then call f with a clone.
function f(env) {
env.x = 3;
g(env.cow());
}
// Create a new environment.
var env = new dyn();
// env -> {__proto__: dyn.prototype}
// Set a value in it.
env.x = 1;
// env -> {x: 1} // Still has dyn.prototype, but it's long so I'll leave it out.
f(env.cow());
// f():
// env -> {__proto__: {x: 1}} // Called with env = caller's env.cow()
// > env.x = 3
// env -> {x: 3, __proto__: {x: 1}} // New value is set in current object
// g():
// env -> {__proto__: {x: 3, __proto__: {x: 1}}} // caller's env.cow()
// env.x -> 3 // attribute lookup follows chain of prototypes
// > env.x = 2
// env -> {x: 2, __proto__: {x: 3, __proto__: {x: 1}}}
console.log(env.x);
// env -> {x: 1} // still unchanged!
// env.x -> 1
I don't think so.
That is not how the language works. You have to use something other than variables to refer to this state information. The most "natural" way being to use properties of this, I guess.
In your case, instead of trying to use dynamic scoping to set the constructor, what if you used the return value?
function Class(clazz) {
return function () {
clazz.apply(this, arguments).apply(this, arguments);
};
}
var Rectangle = new Class(function () {
var width, height;
this.area = function () {
return width * height;
};
// Constructor
return function (w, h) {
width = w;
height = h;
};
});
var rectangle = new Rectangle(2, 3);
console.log(rectangle.area());
Why didn't anybody say this?
You can pass variables from the calling scope into the called function by binding it a context.
function called_function () {
console.log(`My env ${this} my args ${arguments}`, this, arguments);
console.log(`JS Dynamic ? ${this.jsDynamic}`);
}
function calling_function () {
const env = Object.create(null);
env.jsDynamic = 'really?';
...
// no environment
called_function( 'hey', 50 );
// passed in environment
called_function.bind( env )( 'hey', 50 );
Perhaps it's worth mentioning that in strict mode, all functions have no "environment" sent to them by default (this is null). In non strict mode the global object is the default this value for a called function.
You can simulate dynamic scoping using global variables, if you have a way to do syntactic sugar (e.g. macros with gensyms) and if you have unwind-protect.
The macro can appear to rebind the dynamic variable by saving its value in a hidden lexical and then assigning a new value. The unwind-protect code ensures that no matter how that block terminates, the original value of the global will be restored.
Lisp pseudocode:
(let ((#:hidden-local dynamic-var))
(unwind-protect
(progn (setf dynamic-var new-value)
body of code ...)
(set dynamic-var #:hidden-local)))
Of course, this is not a thread-safe way of doing dynamic scope, but if you aren't doing threading, it will do! We would hide it behind a macro like:
(dlet ((dynamic-var new-value))
body of code ...)
So if you have unwind-protect in Javascript, and a macro preprocessor to generate some syntactic sugar (so you're not manually open-coding all your saves and unwind-protected restores) it might be doable.
I know this doesn't exactly answer the question but it's too much code to put into a comment.
As an alternative approach, you may want to look into ExtJS's extend function. This is how it works:
var Rectangle = Ext.extend(Object, {
constructor: function (w, h) {
var width = w, height = h;
this.area = function () {
return width * height;
};
}
});
With public properties instead of private variables:
var Rectangle = Ext.extend(Object, {
width: 0,
height: 0,
constructor: function (w, h) {
this.width = w;
this.height = h;
},
area: function () {
return this.width * this.height;
}
});
var A = {
x : function () { }
};
var b = function (method) {
//want to know method's "parent" here
};
b(A.x);
I want to know that x is defined in A when I call the b(A.x). Is this possible?
There's no nice built-in way to do this, because actually there are no methods in Javascript. They are independent Function objects that just happen to be assigned somewhere.
If you create new instance of function every time (e.g. closure) [thanks Matthew Crumley for pointing that out], then you can modify the function object to explicitly associate it with its parent:
x.parent = A;
and then you can call it properly as if it was a method:
x.call(x.parent);
Otherwise you will have to pass both function and its parent object.
This question makes little sense from the perspective of the language as a function may exist on many objects.
var a = { name : 'a' },
b = { name : 'b' },
c = { name : 'c' };
a.x = function () { alert( this.name ); };
c.x = b.x = a.x; // a, b, and c all reference the same function
You may call the x function with any context you want:
a.x(); // alerts "a" because "this" is object a
b.x(); // alerts "b" because "this" is object b
a.x.call( b ); // alerts "b" because "this" is object b (via parameter)
You can manipulate this behavior to work for you:
var b = function ( method ) {
// parent = this;
};
b.call( A, A.x );
There isn't however any way of knowing from inside a function what object it is assigned to as this isn't necessarily a single place.
Even adding a parent property won't work in all cases, because if the function is in the object's prototype, there is only one copy of the function object, so there's no way to tell which instance it came from. Here's an example to show the problem:
function MyClass() {
// Create a MyClass object
}
MyClass.prototype.x = function() { return 42; };
var a = new MyClass();
a.x.parent = a; // Set the parent to a
var b = new MyClass();
b.x.parent = b; // b.x and a.x both reference the same function from MyClass.prototype
Now, a.x.parent and b.x.parent are both set to b.
#porneL's method will work as long as each object gets its own copy of the function.
It's probably better to modify the function to take a parent object and a method so it will work with any function.
Every function in JavaScript is actually a Function object.
<html>
<body>
<script>
var A = {
x: function (a_a, a_b) { alert(a_a + a_b); }
};
var b = function (a_method) {
alert(a_method.toString());
a_method.call(this, 1, 2);
};
b(A.x);
</script>