Javascript: Need assistance with making a factory-ish function - javascript

I need something like so
function updateRender(ClassName){
if(!(this.currentRender instanceof ClassName)){
doPreprocessing();
this.currentRender = new ClassName();
doPostProcessing();
}
}
So I would be able to call updateRender with a new render object, which can be different type.
updateRender( SolidRender );
updateRender( HollowRender );
updateRender( HollowRender ); //does nothing because currentRender is HollowRender

You've already got your answer in the comments, so this is just an FYI:
You're using this.currentRender, which - if the function is in the global scope - will refer to a variable the global scope. I.e. to the window object of the browser. And putting things in global scope is very rarely a good idea.
Technically, you should put all your code in a single namespace or even inside a function that's invoked immediately so it doesn't pollute the global scope. However, you can start by simply getting the currentRender variable out of the global scope by doing this:
var updateRender = (function () {
var currentRender = null;
return function (klass) {
doPreprocessing();
currentRender = new klass();
doPostProcessing();
};
}());
the updateRender function will still be in the global scope, but at least the currentRender variable is safely hidden inside a closure, so only updateRender can change it (aka privileged access).
As for using klass instead of Class, that's entirely up to you. Using klass is just a common way of getting around the "class is a keyword" problem in Ruby.

Related

Javascript: Global Context and Function Context Declarations

I have noticed something while playing around which has sparked a quick question.
When code is executed in the global/window context, any function declarations get added as methods to the window object.
But when I am in the context of another object, writing a function declaration does not add the method to my objects methods.
function functionInGlobalCtx() { // This will be added as a function to the window object
// code...
}
var myObject = {};
myObject.myObjectFunction = function () {
var $this = this; // The context here is the 'myObject' object
function functionHopefullyInMyObjectCtx() {
// code...
}
}
myObject.myObjectFunction();
Why does the function declaration exist as part of the window object but not the one for the object?
Is this simply 'how JavaScript works' (special rules apply to the global context?) or am I missing something?
Thanks.
Its actually understandable. Function is object. Myobject and myobjectfunction are two different objects. So are 'this' and function itself.
In your example, you define the hopefullyfunction in myobjfunction, not in myobject.
All functions declared globally will be attached to the global window object. That's how JavaScript works.
JavaScript only has function scope. So any function declared inside another function is private to the outer function.
The function functionHopefullyInMyObjectCtx can not be accessed from outside yet.
myObject.myObjectFunction = function () {
var $this = this;
function functionHopefullyInMyObjectCtx() {
// code...
}
}
Declaring a function inside a function does not attach it to the this automatically. However the function remains private and is only accessible within the scope it was declared in.
If you wanted to access the functionHopefullyInMyObjectCtx function from myObject.myObjectFunction then here is a way:
var myObject = {};
myObject.myObjectFunction = function () {
return {
functionHopefullyInMyObjectCtx: function() {
console.log('I got called');
}
}
}
obj = myObject.myObjectFunction();
//obj now has ref to the inner function
obj.functionHopefullyInMyObjectCtx();
I got called
Here is a good read: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions
I believe I have found the answer I was looking for.
Why are variables automatically assigned to the global/window object?
Because the JavaScript engine keeps a 'global environment record' of the items declared within the global scope (just like all scopes have an environment record holding all declaration information), but the difference between the global environment record and normal scope environment records is that the engine makes this record accessible within code (not just for engine internal use), through the window object!
If I am wrong or it's not quite right, please go ahead and correct me.
Thank you for your help.
https://es5.github.io/x10.html#x10.2.3
Difference between variable declaration syntaxes in Javascript (including global variables)?

call or access a local function by name

function f1 () {
console.log('f1')
}
var s = 'f1'
runLocalFunctionByName(s)
Is this possible at all to write runLocalFunctionByName() or just call f1 without typing f1 in the source code, but using a variable holding its name? I mean without modifying f1 into a method, that answer is obvious: just make myobj.f1 = function or declare it globally like f1= function(). I am talking about normal local functions declared with function keyword only, not as vars, global vars or some other object property.
Not without the use of eval, which is evil (when used for this purpose for sure!).
Global functions could be called as attributes of the window object, but if they are in a local/closure scope that's not possible.
If you need to call functions by name, the only proper solution is storing them as attributes on an object, and then using obj[s]() for calling them.
One way of doing this is by using the instantiating a Function object.
var runLocalFunctionByName = function(fName) {
return (new Function('','return '+fName+'();'))();
};
Calling runLocalFunctionByName with a name of a function will now return the output of the named function.
EDIT
In case of local functions, the scope has to be mentioned, so we can modify the code, such that:
var runLocalFunctionByName = function(fName, scope) {
return (new Function('','return '+(scope?scope:'this')+'.'+fName+'();'))();
};
You can't access a local function outside its scope until unless you assign it to a variable having an accessible scope. MDN: A function defined by a function expression inherits the current scope. That is, the function forms a closure. On the other hand, a function defined by a Function constructor does not inherit any scope other than the global scope (which all functions inherit)

Is it possible to Detect Closure Programmatically?

I have a function which allows user to pass a function.
function withPredicate(func){
//...
}
Inside my function, I need to detect whether the func that user pass in has closure or not.
It is not enough to get the function name and search it in window scope. User might pass in an anonymous function without closure like:
var func = function(x){return x;};
withPredicate(func);
EDIT:
I think I need to implement a function which takes a function as a argument and return bool.
function hasClosure(func){
//...
}
so several test cases are:
hasClosure(function(x){return x;}); //return false
var something = 30;
var func1 = function(x){return x.age < something;}
hasClosure(func1); //return false
var Closure = function(){
var something = 18;
var itself = function(x){
return x.age < something;
};
return itself;
};
var func2 = new Closure();
hasClosure(func2); //return true
The last one return true because func2 is not top-level function. When I see some free variable inside the function body like something, it may resolve to the variable defined in its closure other than the one defined in window.
Actually, what I need to do now is to do some manipulations based on the func that has been passed to my function. I can use JSLint to get the undeclared variable. But I also need to resolve these variables. It is acceptable that I can only resolve variables in global scope. But I still need a way to make sure that resolving these variables in global scope is correct. So I need to detect closures.
Is it possible to do that programmatically in javascript?
Alright this is really hacky and probably not worth the effort in actually writing unless your linting or something :)
Basically what you're going to have to do to determine if a function is a closure is call func.toString() which will give you the source of the function. You can then parse the function using some sort of parser which determines all the variables of the function func. You also need to determine and track how these variables are defined. In your criteria in op the criteria for it being a closure is having a variable that is defined outside of function scope and outside of window scope (thus closure scope). So if you can find any variables defined outside of these two scopes we've found a closure.
So heres the pseudocode of hasClosure(), have fun implementing.
func hasClosure(func)
source = func.toString(); //eg "function x(a) {return new Array(a)}"
variables = parseJSForVariables(source)//finds a and Array
for variable in variables:
if(variable not in window)
if(variable not defined in function)
return true //we got a closure
return false //not a closure
The correct answer highly depends on what a "closure" means in this context. The function from the question does not use the variables from the outer scope so, roughly, closure is not created for this function. But strictly speaking, closure is created for any function and binds definition context with the function. So whatever you want to detect, it requires a detailed specification.
But I can assume that the closure here means whether the function references variables declared in outer scope (just like https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Closures specifies). One of the static for analysis libraries can be used for this. For example, JSLint reports used but undeclared variables. Assuming that undeclared variables are just from the upper scope, this indicates that closure is created.

what is self-executing anonymous function or what is this code doing?

var module = {};
(function(exports){
exports.notGlobalFunction = function() {
console.log('I am not global');
};
}(module));
function notGlobalFunction() {
console.log('I am global');
}
notGlobalFunction(); //outputs "I am global"
module.notGlobalFunction(); //outputs "I am not global"
Can anyone help me understand what's going on here? I get that if you call notGlobalFunction(), it will just call the second function.
But what is var module = {} doing? and why is it called again inside the first function?
It says this is commonly known as a self-executing anonymous function but I don't really know what that means.
Immediately invoked functions are typically used to create a local function scope that is private and cannot be accessed from the outside world and can define it's own local symbols without affecting the outside world. It's often a good practice, but in this particular case, I don't see that it creates any benefit other than a few more lines of code because it isn't used for anything.
This piece of code:
(function(exports){
exports.notGlobalFunction = function() {
console.log('I am not global');
};
}(module));
Would be identical to a piece of code without the immediate invocation like this:
module.notGlobalFunction = function() {
console.log('I am not global');
};
The one thing that is different is that in the first, an alias for modules called exports is created which is local to the immediately invoked function block. But, then nothing unique is done with the alias and the code could just as well have used modules directly.
The variable modules is created to be a single global parent object that can then hold many other global variables as properties. This is often called a "namespace". This is generally a good design pattern because it minimizes the number of top-level global variables that might conflict with other pieces of code used in the same project/page.
So rather than make multiple top level variables like this:
var x, y, z;
One could make a single top level variable like this:
var modules = {};
And, then attach all the other globals to it as properties:
modules.x = 5;
modules.y = 10;
modules.z = 0;
This way, while there are still multiple global variables, there is only one top-level global that might conflict with other pieces of code.
Similarly, an immediately invoked function creates a local, private scope where variables can be created that are local to that scope and cannot interfere with other pieces of code:
(function() {
var x, y, z;
// variables x, y and z are available to any code inside this immediately invoked function
// and they act like global variables inside this function block and
// there values will persist for the lifetime of the program
// But, they are not truly global and will not interfere with any other global
// variables and cannot be accessed by code outside this block.
// They create both privacy and isolation, yet work just as well
})();
Passing an argument into the immediately invoked function is just a way to pass a value into the immediately invoked function's scope that will have it's own local symbol:
(function(exports) {
// creates a local symbol in this function block called exports
// that is assigned an initial value of module
})(module);
This creates a new empty object:
var module = {};
It does the same as:
var module = new Object();
This wrapper:
(function(exports){
...
}(module));
only accomplishes to add an alias for the variable module inside the function. As there is no local variables or functions inside that anonymous function, you could do the same without it:
module.notGlobalFunction = function() {
console.log('I am not global');
};
An anonymous function like that could for example be used to create a private variable:
(function(exports){
var s = 'I am not global';
exports.notGlobalFunction = function() {
console.log(s);
};
}(module));
Now the method notGlobalFunction added to the module object can access the variable s, but no other code can reach it.
The IIFE is adding a method to the module object that is being passed in as a parameter. The code is demonstrating that functions create scope. Methods with the same name are being added to a object and the the head object (window) of the browser.
"self-executing" might be misleading. It is an anonymous function expression, that is not assigned or or given as an argument to something, but that called. Read here on Immediately-Invoked Function Expression (IIFE).
what is var module = {} doing?
It initializes an empty object that is acting as a namespace.
why is it called again inside the fist function?
It is not "called", and not "inside" the first function. The object is given as an argument ("exports") to the IEFE, and inside there is a property assigned to it.

Javascript question: about variable definition

I have no idea why it didn't work if I specify a variable with 'var':
like this:
var mytool = function(){
return {
method: function(){}
}
}();
And later I use it in the same template: mytool.method. This will output mytool was not defined.
But if I define it like this:
mytool = function(){
return {
method: function(){}
}
}();
Then it works.
Javascript has function scope. A variable is in scope within the function it was declared in, which also includes any functions you may define within that function.
function () {
var x;
function () {
// x is in scope here
x = 42;
y = 'foo';
}
// x is in scope here
}
// x is out of scope here
// y is in scope here
When declaring a variable, you use the var keyword.
If you don't use the var keyword, Javascript will traverse up the scope chain, expecting to find the variable declared somewhere in a higher function. That's why the x = 42 assignment above assigns to the x that was declared with var x one level higher.
If you did not declare the variable at all before, Javascript will traverse all the way to the global object and make that variable there for you. The y variable above got attached to the global object as window.y and is therefore in scope outside the function is was declared in.
This is bad and you need to avoid it. Properly declare variables in the right scope, using var.
The code you have doesn't show enough to demonstrate the problem. var makes the variable being defined 'local' so it will only be available within the same function (javascript has function level scoping). Not using var makes it global, this is almost always not what you want. You might need to rearrange your code to fix the scope issues.
I take it that you're using this inside of some function:
function setup_mytool() {
var mytool = function(){
return {
method: function(){}
}
}();
}
This creates the variable mytool in the function's scope; when the function setup_mytool exits, the variable is destroyed.
Saying window.mytool or window.my_global_collection.mytool will leave the variable mytool intact when the function exits.
Or:
var mytool;
function setup_mytool() {
mytool = function(){
return {
method: function(){}
}
}();
}
will also do what I think it is you're intending.
The reason why you are getting variable undefined errors is because when you use var, the declared variable is scoped to the surrounding context, meaning that the variable's lifetime is limited to the lifetime of the surrounding context (function, block, whathaveyou).
If you don't use var however, you are effectively declaring a variable tied to global scope. (Usually a Very Bad Idea).
So, in your code, the reason why you are able to access the mytool variable somewhere else in your template is because you tied it to global scope, where in the case of using var, the variable went out of scope because it must have been declared within a function.

Categories