Javascript anonymous closure - return vs window - javascript

I'm learning about anonymous closures and the module pattern. I understand that using a return object will expose some functionality of the module. However there have been some mentions of attaching some functionality to the window/global object.
I was wondering if attaching to the window was a more hacky way of doing a proper return, or had a legitimate use?
var speakingDog = (function() {
var dog = 'spot';
var says = 'woof';
function speak() {
return (dog + ' goes ' + says);
}
return {
speak: speak
}
})();
vs
(function() {
var dog = 'spot';
var says = 'woof';
function speak() {
return (dog + ' goes ' + says);
}
window.speak = speak;
})();

Adding attributes to window is equivalent to creating global variables (since that's actually what it does).
Your first example where you return the object on the other hand encapsulates everything and exposes it via speakingDog in the scope where the code runs. That's much cleaner of course, since you don't create rather meaningless (speak()) globals.

Related

How to call javascript methods that are not in scope but utilise .call(this)

I am unsure on how to call these functions such as inventoryCheck in a web browser (chrome) console when it seems not visible. Is there a way I can call this? Thanks!
Below is a snippet of a javascript file.
(function() {
var CC, addToBagCheck, addToCartError, addToCartRequest, addToCartSuccess, availableSizes, displayCorrectShoe, inventoryCheck, isValidJSON, processInventory, selectSize, showBuy, showError, showSoldOut,
slice = [].slice,
bind = function(fn, me) {
return function() {
return fn.apply(me, arguments);
};
};
inventoryCheck = function() {
return availableSizes(function(product) {
return processInventory(product);
});
};
window.captchaResponse = function(response) {
$('#captcha').addClass('checked');
$('#flashproductform').append('<input class="captcha-duplicate" type="hidden" name="x-PrdRt" value="' + response + '">');
return addToBagCheck();
};
}).call(this);
You cannot. inventoryCheck is defined inside a closure. In order to call them globally (like in the console), you must define them on the window object. Since your closure appears to have window as its context (by calling it using this as context), then you can define inventoryCheck like:
this.inventoryCheck = function(){...}
Note that defining stuff on the global object is a bad idea. Consider attaching everything to a single global object you own. This reduces your footprint on the global object to just a single object. The following pattern is better:
;(function(ns){
ns.inventoryCheck = function(){...}
// the rest of the code
})(this.myGlobal = this.myGlobal || {});
// Usage
myGlobal.inventoryCheck(...);

differences between defining functions/methods in JS?

Here are 3 ways to address the key-value pair of objects constructed using constructor. What are the differences among these 3 ways in every describable aspects? (I would even like to enquiry about basic differences between function & method in terms of their functionality, usage, etc.)
function Person(name,age) {
this.name = name;
this.age = age;
}
var bob = new Person("Bob Smith", 30);
var me = new Person('Madhav Devkota', 55);
//===================================================
//A. Simple function
printPerson= function (p) {
console.log(p.name);
};
printPerson(bob); printPerson(me);
//===================================================
//B. Method I
printPerson = function(){
console.log(this.name) ;
};
bob.printPerson = printPerson; me.printPerson = printPerson;
bob.printPerson(); me.printPerson();
//=================================================
//C. Method II
this.printPerson = function() {
console.log(this.name);
};
bob.printPerson(); me.printPerson();
I would also add
// 0. No function
console.log(bob.name);
console.log(me.name);
It is the most basic way. You are doing something with you object properties directly.
A. Simple function
You are giving your code a name to improve semantics. Now you are describing what your code is intended to do.
You can access more properties and combine to create complex result without code repetition.
printPerson = function (p) {
console.log(p.name + ' is aged ' + p.age)
}
instead of No function
console.log(bob.name + ' is aged ' + bob.age);
console.log(me.name ' is aged ' + me.age);
B. Method I
Now your function is also a property of your object. Unlike simple function which works in scope where it is declared, your method it attached to your object and you can pass it around along with it. When invoked 'this' references the object from which method is invoked.
You can also do a 'nonsense' method like this:
printPerson = function(p){
console.log(p.name) ;
};
bob.printPerson = printPerson; me.printPerson = printPerson;
bob.printPerson(bob); me.printPerson(me);
C. Method II
This one is not quite right. It doesn't make sense in given context as 'this' is at that moment referencing Window object. At then end you are actually calling 'Method I' methods again.
Correct way to use it is in constructor function:
function Person(name,age) {
this.name = name;
this.age = age;
this.printPerson = function() {
console.log(this.name);
};
}
Now your objects have .printPerson() method as soon as they are created.
I could elaborate more if you wish but it's important to notice that function vs method difference is not too relevant at this level of code complexity. When your code gets more complex code organization becomes important. For 'next level' you should get more familiar with Javascript scoping and object inheritance.

the 'this' key word with IIFE in javascript

I was practicing java script from one of the book's examples and encounter following
Code one: here i learnt 'this' key word in javascript references the object that owns the code where 'this' keyword is.
function Vehicle1(theYear, theMake, theModel) {
var year = theYear;
var make = theMake;
var model = theModel;
this.getYear = function () { return year; };
this.getMake = function () { return make; };
this.getModel = function () { return model; };
}
Vehicle1.prototype.getInfo = function () {
return 'Vehicle1: ' + this.getYear() + ' ' + this.getMake() + ' ' + this.getModel();
}
Code two: here i was learning about cretaing namespace using IIFE (Immediately Invoked Function Expression).
(function () {
this.myApp = this.myApp || {};
var ns = this.myApp;
var vehicleCount = 5;
var vehicles = new Array();
ns.Car = function () { };
ns.Truck = function () { };
var repair = {
description: 'changed spark plugs',
cost: 100
};
} ());
I was supposed to execute above codes individually to understand the concepts that the author was trying to explain. But i ended up executing both codes in single file, and i am getting error message in code one stating
Uncaught TypeError: undefined is not a function Vehicle1.getInfo.myApp
Question is: Why or how the IIFE function is trying to put or finding myApp namespace in code one ?
if i execute above 2 codes individually all works as expected.
EDIT
Here is full code just copy past it in html's head section using script tags. I run it in chrome and look in console for error details
function Vehicle1(theYear, theMake, theModel) {
var year = theYear;
var make = theMake;
var model = theModel;
this.getYear = function () { return year; };
this.getMake = function () { return make; };
this.getModel = function () { return model; };
};
Vehicle1.prototype.getInfo = function () {
return 'Vehicle1: ' + this.getYear() + ' ' + this.getMake() + ' ' + this.getModel();
}
(function () {
this.myApp = this.myApp || {};
var ns = this.myApp;
var vehicleCount = 5;
var vehicles = new Array();
ns.Car = function () { };
ns.Truck = function () { };
var repair = {
description: 'changed spark plugs',
cost: 100
};
} ());
i learned 'this' key word in javascript references the object that owns the code where 'this' keyword is.
That is not the case, but it seems kind of like it is.
Warning - the following will sound stupid. That is because javascript this is a really bad language feature (and people should stop using it).
Here's the deal - there's not really such a thing as this. At least not in the way you think it is. It's really a function parameter just like any other.
Let me show you.
let's say you have a function like this
function sayHi(firstName, lastName) {
console.log("Hi", firstName, " ", lastName);
}
Here's two different but pretty much identical ways to invoke it:
sayHi("Fred", "Flintstone");
sayHi.call(null, "Fred", "Flintstone");
this is because all functions have a call method. If you want to, you can write all your function invocations by using .call.
But what's that first null parameter? Well, that parameter is what this will be set to. So if you have:
function sayHi(lastName) {
console.log("Hi", this, " ", lastName);
}
you can say
sayHi.call("Fred", "Flintstone");
So now let me ask you a question. If you can always write all functions using .call, and if .call takes this as a parameter right next to the others, how exactly is this different from any other parameter? Just one that you don't get to name.
But what does the sayHi(...) format do with this then? Since we're not specifying it directly it must come from somewhere. Well, in this form - which is really just a facade for call - javascript takes a guess at what you want it to be. The rules aren't terribly complex, but it's still pretty confusing.
If you're invoking it as an object
var fred = "Fred";
fred.sayHi = sayHi;
fred.sayHi("Flintstone");
is equivalent to
fred.sayHi.call(fred, "Flintstone");
In the case of invoking it directly:
sayHi("Flintstone");
the rules dictate that it will guess that this is the global window object. Unless you're in strict mode, in which case it will be undefined (I think, it might be null).
sayHi.call(window, "Flintstone");
This is what is going on with an IIFE.
Basically, this is a feature that was tacked on to make it look more like Java and is really not necessary for the language at all. Some libraries use it, and you don't have a choice, but I always consult people that when they have control of it they don't use this or new (which is even more confusing) at all.
There is an error because of a missing semicolon after the first code, causing the combined file to be interpreted in a very different way than intended.
Let's simplify the code to see the structure. You have something like:
getInfo = function () {
this.getYear();
}
(function () {
this.myApp = {};
} ());
Without the semicolon after the first function, the parenthesis around the second function are treated as giving the parameters to call the first function:
getInfo = function () {
this.getYear();
}(function () {
this.myApp = {};
} ());
So it's basically as if you wrote:
function getInfo() {
this.getYear();
}
getInfo(function () {
this.myApp = {};
}());
this in both these cases refers to the Window (or the global object) because the function is not being called on an instance. You're calling the second function, which will set Window.myApp, then passing its return value (undefined) to getInfo. getInfo will access this.getYear which doesn't exist so you get the type error.
The error I get here, and with your original code is:
TypeError: this.getYear is not a function
Because this is the global object, then this.getYear is going to be undefined (not a function).
The this keyword in JavaScript is whatever is calling or executing the function. In your example, for a IIFE, this would be the global Window object AKA window
Your question seems to be missing code. Are Car and Truck supposed to extend Vehicle1 or something?
And you have no code calling Vehicle1.getInfo.myApp, so I'm not sure how you could be getting that message.

can prototype functions access local variables?

I thought that functions created using .prototype were supposed to be able to access local variables. Here is what I'm talking about:
function obj() {
var a = "String";
this.innerPrint = function() {
document.write("<p>" + a + "</p>");
};
}
obj.prototype.outerPrint = function() {
document.write("<p>" + a + "</p>");
};
var inst = new obj();
inst.innerPrint();
inst.outerPrint();
What I thought would happen is that both of these functions would do the same thing. But what actually happened is outerPrint doesn't have access to the variable a. Could someone explain to me how you get locals in a prototype function.
Here is a fiddle running this code:
http://jsfiddle.net/Wryte/mxXzg/
By the way, I want to use prototype functions because then each instantiation of the object doesn't have a copy of the function but they each point to the same one.
Of course not, you cannot access one function's locals from another function defined outside the first. It does not matter if the second is defined in the prototype property of the first. Each invocation of your obj function defines a new local a variable, so you cannot avoid having separate copies of the function that needs to access it.
I assume you actually require that variable to be a local and not an instance property, so one possible approach would be to have only a thin local wrapper around your function:
function obj() {
var a = "String";
this.wrapper = function() { outerPrint.call(this, a); }
this.innerPrint = function() {
document.write("<p>" + a + "</p>");
};
}
function outerPrint(a) {
document.write("<p>" + a + "</p>");
};
Again, I assume you have a more complex function in place of outerPrint, so this way you can avoid the duplication of a large function at the expense of duplication of a minimal wrapper. This way you retain the privateness of the a variable, while a public getter would allow external code to inspect its value.
UPDATE: On #Bergi's remark, I've modified the code to make outerPrint a local function in the same scope where the obj constructor is defined. No longer being on the prototype, it will not be directly callable for obj instances. Note that all of the code will need to be inside a function scope, in order to avoid a global outerPrint function.
If you want your variable a to be still accessible after the constructor has finished execution, change your code to
function obj() {
this.a = "String";
this.innerPrint = function() {
document.write("<p>" + this.a + "</p>");
};
}
obj.prototype.outerPrint = function() {
document.write("<p>" + this.a + "</p>");
};
Or define a getter if you don't want to provide direct write access :
function obj() {
var a = "String";
this.getA = function() {
return a;
}
this.innerPrint = function() {
document.write("<p>" + a + "</p>");
};
}
obj.prototype.outerPrint = function() {
document.write("<p>" + this.getA() + "</p>");
};
When you declare 'a' it's declared in the lexical scope of the obj()-function. All instance variables needs to be prototype'd as well, so insted of var a it should be declared as this.a.
No, it is a local variable. Scope rules are not bypassed because of a property named prototype.
The variable is accessible only from functions defined inside the constructor; they are called privileged because of that. Of course, when those are accessible as public methods you can call them from outside, ie.
Obj.prototype.outerPrint = function() {
this.innerPrint();
};

Find out if function is anonymous or is defined in a object

I'm trying to write a helper method in JavaScript. It should act differently if one sends in a function or an reference to a function.
I want to like to use it like this:
helper('div', function () { return false; })
helper('div', obj.fn)
What I can't figure out is: how to inside the helper function tell the difference between the two?
I think it's due to that JavaScript first evaluates the obj.fn before it sends it in.
The only workaround I found is to send the obj.fn as an obj, i.e.
helper('div', { fn: obj.fn })
Then I can tell the difference between the two with typeof. But I really like some way to make it without the extra object declaration.
UPDATED *(AGAIN):
I thought that the toString() method might be your only way forward here. It doesn't however treat a reference of an anonymous object differently.
This code demonstrates that:
function acceptparam(fn){
console.log("fn.constructor = " + fn.constructor);
console.log("typeof fn = " + typeof fn);
console.log("fn toString " + fn.toString());
console.log("fn.prototype = " + fn.prototype);
console.log("fn.prototype.constructor = " + fn.prototype.constructor);
console.log("this[0] = " + this[0]);
console.log("---");
}
function empty(){
return ;
}
var x = {
y : function(){return;}
}
acceptparam(empty);
acceptparam(function(){return;});
acceptparam(x.y);
Very interesting question, without implementing your own solution I dont think you can do it, this post helps to explain why. Its about the parent child relationship only being one way.
http://codingforums.com/showthread.php?t=134855
I thought I'd add another alternative answer, mainly because I didn't want to add to the soup that is my other answer but also because it didn't go down to well with the stackoverflow voters that don't leave constructive comments ;-)
As an alternative to what you're trying to do, you could add a third parameter to the helper function:
function helper (tagName, fn, method)
{
if (method)
fn = fn[method];
//- Do rest of helper function here
}
//- Now if we pass an object method to helper function we can identify it properly
helper('div', obj, "fn"); // method is obj.fn
helper('div', function () { blah(); }); // Still works fine
Merely a suggestion and works as well as or even better than your current work-around.
You can use toString() to find out if the function is anonymous assuming it is declared as a named function and not an unnamed function assigned to a variable:
function jim () { var h = "hello"; }
function jeff(func)
{
var fName;
var inFunc = func.toString();
var rExp = /^function ([^\s]+) \(\)/;
if (fName = inFunc.match(rExp))
fName = fName[1];
alert(fName);
}
Will give you the name of the function if any.
jeff(function () { blah(); }); // alert: null;
jeff(function joe () { blah(); }); // alert: "joe";
jeff(jack); // "jack" if jack is function jack () { }, null if jack = function() {}
My previous edit referred to an IE quirk that didn't exist in other browsers and is no longer valid in IE as of version 9. However, you can still assign named functions as object properties using a named function expression:
var obj = {
fn: function namedFunction () { }
};
This works in all browsers, but IE 8 and lower don't adhere to the specification which says the function is only available by this name inside its own block.

Categories

Resources