Hey guys am a bit confused in running a function from the other. What I have tried is:
var a = (function() {
var babe = function() {
console.log('yay');
};
})();
When I run the code like a.babe() it gives me error like TypeError: Cannot read property 'babe' of undefined. Why is it happening like this?
I want to call the function babe from a ... How can i do it?
I hope you guys can help me ...
Thanks in advance.
You are creating a function called babe and it stays only within the scope of the immediately invoked function expression (IIFE) surrounding it. And since you are not returning anything to the caller, by default, the function call will be evaluated to undefined and that will be stored in a. That is why you are getting the error,
TypeError: Cannot read property 'babe' of undefined
It means that, you are trying to access a property called babe on an undefined value. In this case, a is undefined.
Instead of all this, you can simply return the babe function from the IIFE, wrapped in an object, like this
var a = (function() {
return {
babe: function() {
console.log('yay');
}
};
})()
Now, that the returned object is assigned to a, you can invoke babe function like this
a.babe();
babe is a local variable to the IIFE in that code. It isn't returned. It isn't a property of anything. It isn't accessible.
You have to expose it publicly if you want it to call it from outside that function.
var a = (function() {
var babe = function() {
console.log('yay');
}
return babe;
})();
a();
var a = (function() {
var babe = function() {
console.log('yay');
}
return {
"babe": babe
};
})();
a.babe();
Why have you made a a self executing function? What you want to do is to make a function babe part of an Object a for that, simply do this:
var a = {
babe: function() {document.write('yay');}
}
a.babe();
I have made an object a and added a function babe inside it.. then used the dot notation to access the function inside object a
To use your code you must do
var a = (function() {
var babe = function() { console.log('yay'); }
return babe
})();
a();
To make it a.babe() look at #thefourtheye or #Quentin.
The dot syntax is used to access a "property" of an object. So, in a simple example, you could use something like:
var a = {
babe: function(){ console.log('yay') }
};
a.babe(); // yay
In the case of your example, if you want to create a closure to hide other variables and functions from the global scope, you have to return an object that will then get assigned to a:
var a = (function() {
return {
babe: function(){ console.log('yay') }
}
})();
a.babe(); // yay
Just remember, anytime you use a dot, the variable in front HAS to be an object.
Related
I'm a javascript newbie and trying to understand how functions work. I found a similar question here but it doesn't really answer my question.
Taking the following piece of javascript as an example
var test = function(){
console.log("kick off");
var insideTest = "variable inside test";
var init = function(){
var insideInit ="variable inside init";
console.log("inside init");
}
return{
init:init
}
}
test().init();
The above code prints the following:
kick off
inside init
But if I remove
return{
init:init
}
it gives me an error saying
Uncaught TypeError: Cannot read property 'init' of undefined
Also, even though I'm calling init method using test().init() it doesn't print inside Init if the return statement is removed.
My question is why is it necessary to return init:init to execute init method.
EDIT:
To answer why my init function is inside the test() function here is the larger picture of what i'm trying to do.
var test = function() {
var init = function() {
var a = 0;
function1();
function2();
}
var function1() = function() {
//some code
}
var function1() = function() {
//some code
}
return {
init: init
}
}
Have added inline comments. Also the init inside test will have access to variable defined outside it(init) scope which is closure. test is returning an object to access it's inner function.This specific pattern is revealing module pattern
var test = function(){
console.log("kick off");
var insideTest = "variable inside test";
// Here init is a function which is private to test function
// Any function calling test will not have access to init unless it is 'exposed'
var init = function(){
var insideInit ="variable inside init";
console.log("inside init");
}
return{
init:init // exposing the private function
}
}
When you return, you're returning an Object with a single key of init, which you've assigned the "init" function that you defined within the test function. This allows you to return multiple functions if you'd like, so you can chain calls.
If you'd prefer a different way, you could just return the function without the curly braces, ie. return init;, and then assign the return of test() to a variable. var externalInitFnc = test();
Edit: Looking back it seems that you are fuzzy on the idea of scope in Javascript. When you defined init within the test function, it is only accessible within that function. Similar to how a private variable in a Java class is only available within that same class.
I am currently working on modules but my confusion is that when I code return object in function it can called outside function scope, but when I code standard object like var obj = {some: something} then this can't be called outside the function scope. Why and how?
// Return Object
var ray = (function(){
return {
speak: function (){
console.log("Haseeb");
}
};
})();
ray.speak();
// Standard Object
var ray = (function(){
var obj = {
speak: function (){
console.log("Haseeb");
}
}
})();
obj.speak();
Assuming that you meant to write ray.speak(); instead of obj.speak();;
// Standard Object
var ray = (function(){
var obj = {
speak: function (){
console.log("Haseeb");
}
}
})();
In this snippet, when anonymous function is executed it returns nothing back to ray variable, so when you try to access speak() method from ray, it throws an error saying Cannot read property 'speak' of undefined.
But in your first snippet, the anonymous function does return an object with speak method so you can call, ray.speak().
// Standard Object
var ray = (function(){
var obj = {
speak: function (){
console.log("Haseeb");
}
}
})();
obj.speak();
This does not work because of how lexical scoping works. Obj on the outside has no context to what is defined inside of the function because the obj is declared inside the block scope of the function. If, however obj was declared in the same scope, it will work as expected.
var obj;
// Standard Object
var ray = (function(){
obj = {
speak: function (){
console.log("Haseeb");
}
}
})();
obj.speak();
ray.speak() will not work because it does not have a binding to obj.
return obj={...} will be a solution for this problem.
Understanding JavaScript variable scope would help:
http://www.w3schools.com/js/js_scope.asp
Now coming to your code.
In the first snippet, the variable 'ray' gets assigned the value returned by the the self executed function, which is the object returned. It is similar to this:
var ray = {
speak: function (){
console.log("Haseeb");
}
};
So now the statement below is valid as 'ray' has a property 'speak'
ray.speak();
However, in the second part of the snippet, nothing is returned by the self executed function, so, it is similar to:
var ray = undefined;
Now the statement 'ray.speak()' is same as executing 'undefined.speak()', which would throw an error, obviously.
Also, executing obj.speak is same as executing 'undefined.speak()', because the variable 'obj' is only available inside that self executing function. Outside the function, 'obj' is not defined.
Hope this helps. :)
Edit:
Explanation for your question about the return statement:
The return statement returns whatever is the output of the code/statement in front of it.
Examples:
var a = 2;
return a; // will return a's value, i.e. '2'
var obj = { x:1 };
return obj; // will return the obj variable's value i.e. { x:1 }
var a = 1;
return a > 1; // will return false i.e. what 'a > 1' outputs after execution
so if you write
return obj = { x:1 };
this will return what the assignment 'obj = { x:1 }' outputs, which is obj's assigned value.
Now coming to your code
var ray = (function(){
return obj = {
speak: function (){
console.log("Haseeb");
}
}
})();
Here the return statement doesn't make obj available to the scope outside the function, it just returns the value of obj, which is then assigned to 'ray'.
The reason that you are able to do obj.speak() without getting any exceptions is that you have used the variable obj without declaring it inside the function using 'var' keyword, which results in 'obj' getting automatically declared in the global scope. And that is why you are able to access 'obj' outside of the function too.
If you change your code to this:
var ray = (function(){
var obj;
return obj = {
speak: function (){
console.log("Haseeb");
}
}
})();
You will get exception while trying to execute obj.speak() outside the function. Because 'obj' is now declared and available only inside the function.
I would suggest reading some more tutorials about variable scope in JavaScript and playing around a bit on the console. :)
Hope this helps :)
I want to know how the function has been initialized, with the expression or declaried as fuction. _ Amazon interview question
expression : var a = function (){ }
declaration: function a (){ }
You could just do a.toString() and parse out the name. Or do the same with regular expressions
a.toString().test(/^\s*function\s*\(/);
function a(){ }; // gives false
var a = function (){ }; // gives true
Of course as Grundy pointed out this fails with named functions. Something like
var a = function b() {};
or
function b() {};
var a = b;
And ES6 has .name (see the Browser table at the bottom for the current state of affairs) - https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Function/name
I don't think it's possible to do so. The only difference between:
var func = function(){ };
and:
function func() { };
Is that the first one gets assigned on runtime. The way I see it, is that both function statements return a reference to their respective function objects. In that sense they are both the same. The only thing you could argue is that one is not named and the other one is, but you could have assigned a named function to a variable too.
However, there seems to be a difference on how they get assigned. The second one seems to get assigned to a variable that its named after, right at the start of the execution context. The first one has to wait for the explicit assignment within the execution context.
So you'd be testing for when they get assigned. You might think that's is possible to do so within the global object like:
//some protected vars that can't work without same-origin
var protected = ['caches', 'localStorage', 'sessionStorage', 'frameElement'];
var definedAtInit = [];
for(prop in window){
if(!isSandboxed(prop) && typeof window[prop] === 'function'){
definedAtInit.push(prop);
}
};
function isSandboxed(prop){
return protected.indexOf(prop) !== -1;
}
function isItDefinedAtInit(funcName){
return definedAtInit.indexOf(funcName) !== -1;
}
var func = function() {
console.log('test');
}
var results = { isItDefinedAtInit : isItDefinedAtInit('isItDefinedAtInit'),
func : isItDefinedAtInit('func')
};
document.getElementById('results').innerHTML = JSON.stringify(results, '/t');
<pre id="results"></pre>
However, you could still do something like:
var isItDefinedAtInit = function() { };
//After this, isItDefinedAtInit('isItDefinedAtInit') would be wrong.
And you still have the problems with other execution contexts, I don't think functions declared within a function execution context get attached to any object.
I think these kind of checks are a bad idea to be honest.
There is only way, we can determine function has defined with function declarations not as expression.
as Grundy mentioned name property of the respective function gives require information, if it has been defined with expression name property holds undefined value, else it holds function name.
Here is the code :
var isDefinedAsFunction = function(fn){
return fn.name !== undefined
}
I want to be able to assign a property to a function inside the function itself. I do not want to assign it to the object of invocation. So I want the equivalent of doing this:
var test = function() {
return true;
};
test.a = 'property on a function';
alert(test.a);
Instead of this, where the property is assigned to a global object:
var testAgain = function() {
this.a = "this property won't be assigned to the function";
return true;
};
testAgain();
alert(window.a);
Edit: To clarify, I'm wondering if there's something like this:
var test = function() {
function.a = 'property on a function';
};
alert(test.a); // returns 'property on a function'
Without knowing that the function is called test or having to execute it.
I know of course this isn't valid syntax
[is there a way to set a property on a function] without knowing that the function is called test or having to execute it.
Emphasis mine.
You can set a property on a function without knowing what its global variable name is necessarily going to be, however you do have to have a reference to the function in one way or another.
The module pattern is as close of a fit as I can think of:
window.test = (function () {
//the function could be named anything...
function testFn() {
...code here...
}
//...so long as the same name is used here
testFn.foo = 'bar';
return testFn;
}());
window.test.foo; //'bar'
The outer closure prevents testFn from being accessed anywhere globally, so all other references will have to use window.test.
This part of the answer is associated with the prior version of the question.
The simplest way of doing this is to use a named function:
var test = function testFn() {
testFn.foo = 'bar';
return true;
};
test.foo; //undefined
test();
test.foo; //'bar'
A better way of doing this is to use the module pattern so that you don't accidentally create issues with global leakage:
var test = (function () {
function ret() {
ret.foo = 'bar';
return true;
}
return ret;
}());
test.foo; //undefined
test();
test.foo; //'bar'
var testAgain = function() {
arguments.callee.a = "this property won't be assigned to the function";
return true;
};
testAgain();
alert(testAgain.a);
You can do this by simple using the name to assign the property like this:
var test = function () {
test.a = 'a';
return true;
};
When test is invoked, the property will be set.
Demo
You could use arguments.callee, as su- said, but that's considered really bad practice. Also, it won't work in strict mode.
var test = function() {
test.a = 'a';
};
Or you can use prototypes, read more here.
http://jsfiddle.net/ZLH7J/1/
What the jsFiddle and code below shows are two examples that essentially do the same thing. When trying to call first(); or this.first(); in either example, an undefined error is thrown. I can call the functions later through the instance, but not when trying to instantiate the object using init(){...}() like a constructor. I put init() at the bottom thinking it was an order of operations thing, but that is not the case. This does not work the way I thought it would work.
I am curious to understand how this is supposed to be done, and why this cannot be done.
//create and return an obj
var fishSticks = function(){
return {
first: function(){
document.getElementById('output').innerHTML="Success";
},
init: function(){
try{
first(); //err
this.first(); // also err
}catch(e){
document.getElementById('output').innerHTML=e.toString();
}
}()
}
}
//do function stuff and then return 'this'
var fishFillet = function(){
var first = function(){
document.getElementById('output2').innerHTML="Success";
}
var init = function(){
try{
first(); //err
this.first(); // also err
}catch(e){
document.getElementById('output2').innerHTML=e.toString();
}
}()
return this;
}
var test = new fishSticks();
var test2 = new fishFillet();
You need to understand two things:
1) JavaScript does not automatically insert this like Java does, so the first() call will only look through the lexical scope for a definition of first, it will nok look at the this object. Therefore the call to first() should work but this will be bound to something else than what you might expect inside first.
2) Local variables in a constructor do not become members of the constructed object.
In your second example, if you comment out the call in "init" to this.first() then you get the "Success" message.
The first version doesn't work because JavaScript simply does not allow for references to be made within an under-construction object to the object itself. There's just no way to do it.
The second one works (well the simple reference to "first" works) because "first" is declared as a local variable. Local variables are not properties of any object, and in particular they're not properties of the object allocated when the function is called with new. That's why this.first() doesn't work.
In the second one, you could make this.first() work by declaring things differently:
var fishFillet = function(){
this.first = function(){
document.getElementById('output2').innerHTML="Success";
}
var init = function(){
try{
this.first(); //will work
}catch(e){
document.getElementById('output2').innerHTML=e.toString();
}
}()
return this;
}
Also, for what it's worth, the weird anti-pattern of
var something = function() { ... }
is not as useful as
function something() { ... }
There's no reason to use the var declaration instead of the function declaration.
How about...
var fishFillet = function () {
var first = function () {
document.write( 'Success' );
};
var init = function () {
first();
};
init();
return {
first: first
};
};
And then:
var ff = fishFillet(); // calls init() which calls first()
ff.first(); // call first() manually
Live demo: http://jsfiddle.net/uaCnv/
So, first you define all your functions, next you manually invoke init, and last you return an object containing those functions which should be available through the resulting object (as methods).
Since you are using both as a constructor, format them as such:
function fishFillet(){
this.first = function(){
document.getElementById('output2').innerHTML="Success";
}
this.init = function(){
try{
this.first();
}catch(e){
document.getElementById('output2').innerHTML=e.toString();
}
}
}
var food = new fishFillet();
food.init();
The reason it wasn't working for you is b/c "first" is created as a local varaible, and is deleted after execultion. Init isn't being called until after the execution of the constructor has finished