For the sake of maintaining a namespace, I have code that looks something like this:
MyNamespace = function() {
var foo;
//other private vars
//some private functions
//return certain functions which will be publicly called through MyNamespace
return {
"pubFunc1": function() {/*do stuff*/}
}
}
I'd like one of my public functions to be able to take a function as a parameter. The function being passed in would look something like this:
function(state) {
//do something with the passed in state
}
This function would be passed into the first anonymous function. From there, as implied by the parameter, the first anonymous function would pass its state (with this) to the function that was just passed in. The problem I run into is that the this of an anonymous function refers to the global window, not to the anonymous function.
What I really need is the ability to pass in a function and give it full access to the private variables and functions within my namespace function. Does anyone know a good way to do this?
Javascript uses lexical scoping, that is, only functions physically located inside an outer function have access to its scope (vars). There's no way to make function's vars accessible for any function defined outside.
So your only option to make "private" vars into "protected" properties and pass the properties bag to the callback:
MyNamespace = function() {
return {
_foo: "something",
_bar: "else",
pubFunc1: function(callback) {
callback(this._foo, this._bar) //or
callback(this)
}
}
}
Related
I always thought that nested function invocations had access to the scope above them regardless of where the function was defined (in the below example I thought the printsomething function would have access to the "something" variable in the runeverything function). According to the below fiddle this is not the case. Does the function printsomething have to be defined (and not just invoked) within the outer function runeverything to have access to local variables defined within the other function runeverything?
This is important for me now because node modules are hoisted to the top when they are imported. This creates scoping problems for me!
function foo(){
function printsomething() {
$('#test').text(something || 'nothing');
};
var something = 'something';
function runeverything() {
printsomething(); //returns "something is not defined"
}
runeverything();
};
foo();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<h1 id="test"></h1>
You need to have those functions embedded in another function in order to do that:
i.e:
function foo() {
function printsomething() {
$('#test').text(something || 'nothing');
};
function runeverything() {
printsomething(); //returns "something"
}
var something = 'something';
runeverything();
};
foo();
This way it will work since the scope of variable something is for function foo, where your functions are defined also.
Yes.
Scope is determined by where the function is defined and not by where it is called from.
To get access to data from the scope where a function is called: pass it as an argument.
In my knockout.js project I wrote some self invoking functions like this:
var addMarkers = function () {
ko.utils.arrayForEach(self.sectionList(), function (sectionItem) {
ko.utils.arrayForEach(sectionItem.placeList(), function (placeItem) {
placeItem.marker.addListener('click', function () {
map.panTo(placeItem.marker.getPosition());
});
});
});
}();
The function works without problems, however in JSLint the "var addMarkers" was highlighted as unused variable. That makes me wonder if I should the function like this, or just make anonymous because it is a better practice?:
function addMarkers (){ code to be executed };
Assigning the result of a self-executing function is often useful. In particular, I like to define my main viewmodel this way, because
I don't need a prototype for my viewmodel
I'm not likely to need more than one instance of a viewmodel
The reason you would use a self-executing function is that you need a local scope for whatever you're doing, to isolate it from surrounding scope. The reason you would assign a variable from it is that you want it to return a value you will use later. In your example, neither of these is true.
So I was getting the following error:
TypeError: parentRef.parentFunction() is not a function
in my callee.
My callee looked sort of like this
function callee(parentRef){
function subRoutine(){
//stuff
parentRef.parentFunction(params);
}
}
And the caller looked like this:
function caller(){
refToCallee = new callee(this);
refToCallee.subRoutine();
parentFunction(prms){
//other stuff
}
}
Then I realized that I had seen code that changed the caller to have the following line when defining parentFunction
this.parentFunction = function(){ etc.}
What is the thiskeyword doing here. Is it a namespacing thing? More specifically why does my first definition without using the this.funcName syntax not work?
When you define a function like parentFunction inside another function like caller, there are 3 ways of doing it.
function parentFunction() { ... }
var parentFunction = function() { ... };
this.parentFunction = function() { ... };
The first declares a function inside the scope of caller. It is only usable inside caller.
The second declares a local variable that happens to be a function, it is also only callable inside caller.
The third declares a property on the caller object that happens to be a function. Anyone with a reference to a caller object (like in your example) can call it. This is why the this.parentFunction is needed for callee to be able to use it.
What you have in your original example,
parentFunction(prms) { ... }
is not proper javascript. It does not declare a variable or a function, nor does it execute any code.
It appears you want a callback like this:
function callee(callback){
//stuff
callback(params);
}
function caller(){
callee(callback);
function callback(prms){
//other stuff
}
}
can someone please explain what the difference is between these two functions?
(function(Engine, $, undefined) { //hidden from scope
//public function below
Engine.Init = function() {
console.log("IM PUBLIC");
}
//anonymous functions below
function Login() {
console.log("IM PRIVATE");
}
})( window.Engine = window.Engine || {}, jQuery );
Specifically, I'd like to know why Engine.Init() is available in the Console but Login isn't.
Init is a property of the Engine object that refers to a function.
You can access it like any other property.
Login is a local variable within the anonymous, "immediately invoked function expression" (IIFE); like other local variables, its name is only visible within the declaring function
Engine is global because of the parameters:
(window.Engine = window.Engine || {}, jQuery)
and available in the global namespace, if you did:
Engine.Login = function(){}
That would be available globally.
The function Login is only available inside the scope of the anonymous self executing function.
There is not really a difference between the functions themselves. The only difference is that the first function is assigned to a property of an object (Engine.init) defined in global scope (window.Engine), whereas the second function is defined locally inside the immediately invoked function expression (IIFE).
Here is a equivalent, but simpler example:
function foo() {
// 1
window.globalFunc = function() {
// global/public
}
// 2
function localFunc() {
// local/private
}
}
foo();
Because the first function is explicitly assigned to a global variable, it can be accessed outside of foo, after foo was executed. localFunc is not exported and hence local to foo, i.e. it cannot be accessed and doesn't exist outside of foo.
This thing
function(Engine, $, undefined) {
...
}
is actually a closure. So everything define inside that function is available only in that scope. When you do
Engine.Init = ...
You create a property which is attached to Engine object. In your case Engine is a global object, which means that you have an access to it via the console.
I passed a function(which itself has a parameter let's say para) as a parameter into another function function b() and how to get the parameter para.
here is the simple example
<input type="button" onclick="sometest3()" value="Run test">
<script>
function sometest3() {
// pass an anonymous function as a parameter which has
// its own parameter "client"
sometest('connection',function(client){client.getInfo();})
}
function sometest(eve,func) {
// get this function's parameter which is "client" and pass
// a reference of sometest2 to it. so in the callback I can use
client.getInfo();
}
function sometest2() {
this.getInfo=function (){alert("get it");};
}
</script>
You can't given the code you've posted. The anonymous function passed to sometest is held as a local variable that is inaccessible to functions outside its scope.
If you want sometest to access client, you must pass it, the following uses local variable:
function sometest3() {
var client = {getInfo: function(){ /* whatever */}};
sometest('connection', function(client){client.getInfo();}, client);
}
function sometest(eve, func, client) {
// The client object has been passed from sometest3
func(client);
}
Or you could make it available to both functions in a closure or global variable, or property of some object accessable to both functions (essentially these same thing). Your choice.
e.g. using a closure:
var foo = (function() {
var client = {getInfo: function(){ /* whatever */}};
return {
sometest3: function() {
foo.sometest('connection', function(obj){obj.getInfo();}, client);
},
sometest: function(eve, func, client) {
// The client object has been passed from sometest3
func(client);
}
};
}());
Then call it as foo.sometest3().
Edit
Added call
If you want to know how many arguments are named in a function func you can check func.length. And this doesn't mean that you can't pass more or less arguments to that function, of course, but only how many of them are stored in local scoped variables.
But if you want to know the names of those variables the best thing to do is to convert the function to a string and get its declaration:
var parms = String(func)
.match(/function[^\(]*\(([^\)]*)/)[1]
.split(/\s*,\s*/);
(Mind you that putting comments between the function keyword and its declaration may mess up this method.)
That being said, I fail to see how this can be useful for you...