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.
Related
the following function takes an object and returns a function. the function it returns is a higher order function that takes a callback function.
const deconstruct = function (object) {
const declarations = Object.entries(object).reduce(function (string, entry) {
const key = entry[0];
const value = entry[1];
const declaration = "const " + key + " = " + value + ";";
return string + declaration;
}, "");
const execute = function (callback) {
return Function(
declarations
+ "return "
+ callback.toString()
+ "();"
)();
};
return execute;
};
execute augments callback by making it part of a new function. the new function declares constants, runs callback and returns the result. because in the new function the constants declared and callback are in the same scope, callback can access those constants, thus effectively injecting those constants into the scope of callback. here’s an example of an invocation of deconstruct.
deconstruct({
a: 0,
b: 1,
c: 2
})(function () {
console.log(a, b, c); // 0 1 2
});
but is there a different way to inject variables into the scope of a function without using intermediary strings like my code does?
Based on your revised information in the question, I see now that the purpose was to keep it DRY (Don't Repeat Yourself). The goal was to avoid repeating (a,b,c) unnecessarily, imagining that there may be hundreds of properties.
Here's one strategy. You could make use of the with statement to bring this into scope and bind the object to the function.
values = { a: 0, b: 1, c: 2 };
function foo() {
with(this) {
console.log(a,b,c);
}
}
foo.apply(values);
// or
let bar = foo.bind(values);
bar();
Or for a one-time use, you can just define the function with the values in scope:
values = { a: 0, b: 1, c: 2 };
with (values) foo = () => {
console.log(a, b, c);
}
foo();
I meet a problem about dynamic dispatch. The following is the code snippet which from the book [Programming JavaScript Applications], and I put it on https://jsfiddle.net/abramhum/bbfxxwok/1/
function equals(a, b, c) {
console.log("a[=]" + a);
if (a == b) {
console.log(c);
}
}
function test(a, fn) {
console.log(a + " ---start function[=]");
fn.apply(this);
console.log(a + " ---Fnished");
}
var methods = {
init: function(args) {
return 'initializing...';
},
hello: function(args) {
return 'Hello, ' + args;
},
goodbye: function(args) {
return 'Goodbye, cruel ' + args;
}
},
greet = function greet(options) {
var args = [].slice.call(arguments, 0),
initialized = false,
action = 'init'; // init will run by default
if (typeof options === 'string' &&
typeof methods[options] === 'function') {
action = options;
args.shift();
}
return methods[action](args);
};
test('Dynamic dispatch', function() {
var test1 = greet(),
test2 = greet('hello', 'world!'),
test3 = greet('goodbye', 'world!');
equals(test2, 'Hello, world!',
'Dispatched to hello method.');
equals(test3, 'Goodbye, cruel world!',
'Dispatched to goodbye method.');
});
There exist two subjects in this problem, one is when greet("goodbye", "world") is executed, why it called greet(options), and the value about options is indeed the fist parameter, like "goodbye", and the "world" can be get via arguments; The second is var methods ={...}, it get the arguments like init, and return the value if matching the declare, like init:function(args){...}, but it indeed not code style of switch, and why we can use that in javascript.
This is much unlike C codes, I don't know why, is any one know the reason?
thanks.
one is when greet("goodbye", "world") is executed, why it called greet(options), and the value about options is indeed the fist parameter, like "goodbye", and the "world" can be get via arguments
Because in a JavaScript non-arrow function, arguments is a predefined identifier referring to a pseudo-array of all of the arguments passed to the function. It has nothing to do with dynamic dispatch. It's just a feature of JavaScript functions that was useful back before JavaScript got proper variable parameter lists:
function foo() {
console.log("foo called, total arguments: " + arguments.length);
for (var n = 0; n < arguments.length; ++n) {
console.log("Arg #" + n + ":", arguments[n]);
}
}
foo();
foo("bar");
foo("biz", 42);
the second problem is var methods ={...}, it get the arguments like init
Those aren't arguments, those are properties being defined for the object assigned to methods. Just like a, b, and c here:
var obj = {
a: 42,
b: "Whatever",
c: "just cuz"
};
...and return the value if matching the declare, like init:function(args){...}, but it indeed not code style of switch, and why we can use that in javascript.
Because functions are objects, and so like any other object, you can refer to them from variables, arguments, and object properties. methods's properties init, hello, and goodbye refer to functions. You can call them via the properties: method.init().
So say we have the variable name containing "init". We can look up the property with that name on methods: methods[name]. And since that gives us a reference to a function, we can call that function.
var methods = {
init: function() {
console.log("init called");
}
};
var name = "init";
methods[name](); // "init called"
More: Dynamically access object property using variable
This is much unlike C codes, I don't know why, is any one know the reason?
Because C and JavaScript are fundamentally different languages, created with different design constraints, at different times, by different people, with different priorities and limits.
I thought I understood scope however, while thinking of a particular code problem I had, I am confused by the following:
var a = {
aFunc: function() {
console.log(x);
}
};
var b = {
bFunc: function() {
var x = c.x;
console.log(x);
a.aFunc();
}
};
var c = {
x: 'x is in c'
};
b.bFunc();
Question: aFunc is called inside bFunc, why do I get 'x is not defined' inside aFunc? Isn't this a simple closure where a.aFunc can access b.bFunc scope?
Isnt this a simple closure where a.aFunc can access b.bFunc scope?
No. Closure is a property of the functions which encloses over all the variables in their scope, during their definition, not during their invocation.
In your case, when a.aFunc is called, it doesn't enclose the variables in b.bFunc because, it is just invoked there, not defined there.
Let's try to understand this, with this example
function Test1(func) {
var a = 0;
func();
}
function Test() {
var a = 5;
Test1(function() {
console.log(a);
});
}
Test();
will print 5, because when func() is executed, the actual function object has enclosed over the variables in Test, since the closure happens during the function definition.
No, every function has it's own scope. A function call doesn't share it's scope with it. If you want to share variables via scope you have to put them in the shared scope like this:
var x = 'x from shared scope';
var a = {
aFunc: function() {
console.log('aFunc: ' + x);
}
};
var b = {
bFunc: function() {
var x = 'x only in scope b';
console.log('bFunc: '+ x);
a.aFunc();
}
};
b.bFunc();
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.
var a = {
b: {
aa: 'hello',
bb: 'you',
cc: 'guys'
}
}
var b = function(){
$.each(a.b, function(x){
if( $.isFunction(x) == 'function' ){
alert(x);
};
});
};
var aa = function(){
var dude = 'hi there';
}
b();
I have an each loop inside the b function.
What i would like to do is loop through the a.b values, and find if a function exists with it's name. In this case the only one that should trigger is 'aa' as function 'aa exists.
is the isfunction line correct? or would typeof work?
In this case the only one that should trigger is 'aa' as function 'aa exists.
$.each() is iterating members of the Object passed to it. And, currently, the function aa is not a member of the Object a.b.
$.isFunction() isn't returning true because every member of a.b has a String value:
aa: 'hello',
bb: 'you',
cc: 'guys'
If you want the function as a member of the Object, you'll need to set it as the value of one of its properties:
a.b.aa = function () {
var dude = 'hi there';
};
This will replace the 'hello' value with a reference to the function.
To reuse the property names to lookup globals, you can use them on the global object (window in browsers).
var key = 'aa';
var val = window[key];
var b = function () {
$.each(a.b, function (key) {
if (key in window && $.isFunction(window[key])) {
alert(key + ' is a global function.');
}
});
};
Example: http://jsfiddle.net/cAaMf/
Though, note the "No wrap - in <body>" in the options of the Fiddle. This will only work for globals as no other scope object can be accessed within code.