the 'this' key word with IIFE in javascript - 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.

Related

Is it possible to make a function self aware without external input

Background
I want a function keeping track of its own state:
var myObject = {
myFunction: function () {
var myself = this.myFunction;
var firstTime = Boolean(!myself.lastRetry);
if (firstTime) {
myself.lastRetry = Date.now();
return true;
}
// some more code
}
}
The problem with the above code is that the value of this will depend on the site of the function call. I want the function to be able to refer to itself without using:
myObject.myFunction
.bind()
.apply()
.call()
Question
Is it possible to give a function this kind of self awareness independent of its call site and without any help from external references to it?
If you want to store that state on the function instance, give the function a name, and use that name within it:
var myObject = {
myFunction: function theFunctionName() {
// ^^^^^^^^^^^^^^^--------------------- name
var firstTime = Boolean(!theFunctionName.lastRetry);
// ^--------------------------- using it
if (firstTime) {
theFunctionName.lastRetry = Date.now();
// ^------------------------------------------------ using it
return true;
}
// some more code
}
};
You'd do that whenever you want to use a function recursively as well. When you give a name to a function that way (putting the name after function and before (), that name is in-scope within the function's own code. (It's not in-scope for the code containing the function if it's a function expression, but it is if it's a function declaration. Yours is an expression.)
That's a named function expression (where previously you had an anonymous function expression). You may hear warnings about NFEs, but the issues various JavaScript implementations had with them are essentially in the past. (IE8 still handles them incorrectly, though: More in this post on my blog.)
You might consider keeping that state somewhere private, though, via an IIFE:
var myObject = (function(){
var lastRetry = null;
return {
myFunction: function() {
var firstTime = Boolean(!lastRetry);
if (firstTime) {
lastRetry = Date.now();
return true;
}
// some more code
}
};
})();
Now, nothing outside that outer anonymous function can see lastRetry at all. (And you don't have to worry about IE8, if you're supporting stubborn XP users. :-) )
Side note: The unary ! operator always returns a boolean, so your
var firstTime = Boolean(!theFunctionName.lastRetry);
...is exactly equivalent to:
var firstTime = !theFunctionName.lastRetry;
...but with an extra unnecessary function call. (Not that it hurts anything.)
Of course you can, simply give your function an internal named representation and it can refer to itself from there. For example...
var obj = {
doThings:function doThingsInternal(arg1, arg2) {
console.log(arg1, arg2);
for (var arg in doThingsInternal.arguments) {
console.log(arg);
}
}
};
obj.doThings('John', 'Doe');
You could use a simple Closure, if you are not too bent on keeping state existence knowledge within the function. But I guess you don't want that. Another way to do this could be changing the function itself on the first call. Benefits, no/less state variables needed and no costly checks on subsequent calls! -
var myObject = {
myFunction: function () {
// Whatever you wanna do on the first call...
// ...
// And then...
this.myFunction = function(){
// Change the definition to whatever it should do
// in the subsequent calls.
}
// return the first call value.
}
};
You can extend this model to any states by changing the function definition per your state.

Why compiler doesn't translate "this" link into context-agnostic variable?

Suppose I have a class (very simple scenario)
class Student
{
name = "John";
sayHello()
{
console.log("Hi, I'm " + this.name);
}
}
It's compiled by TypeScript compiler to:
var Student = (function () {
function Student() {
this.name = "John";
}
Student.prototype.sayHello = function () {
console.log("Hi, I'm " + this.name); //here is the problem. Accessing name via this
};
return Student;
})();
Now if I create an object and call a method, everything works fine.
var student = new Student();
student.sayHello(); //prints Hi, I'm John
But if I invoke that method from callback, it breaks (this is referencing a Window as expected)
setTimeout(student.sayHello); //prints Hi, I'm
I'm aware of the difference between this in JavaScript and C# or Java. I'm also aware, that TypeScript tries to address this difference. For example this code:
class Student
{
name = "John";
sayHelloTo(other)
{
other(() => this.name);
}
}
Would have been compiled to
var Student = (function () {
function Student() {
this.name = "John";
}
Student.prototype.sayHelloTo = function (other) {
//note, the compiler solves the problem by capturing this into local variable
var _this = this;
other(function () {
return _this.name;
});
};
return Student;
})();
Why isn't the compiler creates something like _this variable in the first scenario for class members? I would expect to see something along next code (not a real output and this code is not correct either, just to show my intention)
var Student = (function () {
var _this;
function Student() {
_this = this; //solves the problem of setTimeout(student.sayHello)
_this.name = "John";
}
Student.prototype.sayHello = function () {
console.log("Hi, I'm " + _this.name);
};
return Student;
})();
I've used the TypeScript v0.9.7 compiler
You might want to change the sayHello function like below to make it generate to code you want. Notice the sayHello = () => { }
This will still work with multiple students which is not the case with your example.
class Student
{
name = "John";
sayHello = () =>
{
console.log("Hi, I'm " + this.name);
}
}
It will generate code like this:
function Student() {
var _this = this;
this.name = "John";
this.sayHello = function () {
console.log("Hi, I'm " + _this.name);
};
}
Another possibility is to change the call to setTimeout like this
setTimeout(() => { student.sayHello() });
The only thing that the compiler could do would be to make sure each constructed object had a bound copy of the prototype functions. That would involve a very significant semantic change, so it can't really do that.
The translated code returns a function that has access to a closure, it's true. However, in your suggested alternative, there's only one _this that would be shared by all instances created by the constructor. The closure is in that function that is called to create the "Student" constructor; that function only runs once, when the constructor is made, and then never again. Thus each call to new Student() would update that single, shared variable _this. (In the example, the way that would cause a problem would be for the "name" property to change on a Student instance. If they all are named "John" it doesn't matter :)
The fundamental issue is that in JavaScript, there is no intrinsic relationship between a function and any object. When you call
setTimeout(student.sayHello, 100);
the first parameter expression evaluates to a plain reference to that "sayHello" function. The fact that the reference came from the object is lost. I suppose another alternative for Typescript would be to catch those sorts of expressions and create a bound function at that point. That is, the class code itself would remain the same, but the setTimeout() call would be translated as
setTimeout(student.sayHello.bind(student), 100);
What sort of ramifications that would have on everything I can't say. I also don't know how hard it would be for the compiler to know that it should do that transformation; there might be times at which it doesn't make sense.

Having trouble extending a Javascript function with more functions

I'm trying to override a Javascript function that is included in a .js file that I cannot modify(it is served from a server our applications aren't deployed on). The function contains functions and variables within it. There is one sub-function that I need to change the behavior of but it is called by another, I can't call it directly. Here it is:
Simplistic version of included file that I can't change:
com.company.topLevelFunc = function () {
var a = null;
var b = null;
var doSomething = function() {
a = foo;
b = bar;
};
var get = function(cfg) {
//do stuff
};
return {
//other vars and functions here
getValue : function (cfg) {
cfg.url=a + b;
get(cfg);
}
};
}();
The function I need to override is the get(cfg). However, I can't call it directly, I need to go through the getValue(cfg) method and preserve all the other stuff that goes on in the top level function. So I've been trying to override both as follows:
My JS that I full control over, and doesn't work, it errors on the apply saying that 'missing : after property id". Am I doing this correct, not sure how to get the apply to work correctly?
var topLevel = com.company.topLevelFunc;
myTopLevel = function() {
var myGet = function(cfg) {
//do simliar but different stuff from the original get function
};
return {
topLevel.apply(this, arguments);
getMyValue : function (cfg) {
cfg.c= a + b +"some other string";
//do something
myGet(cfg);
}
};
}();
Unfortunately for you, the get method is private. It only exists inside the body of a an anonymous function nobody has access to. Aside from some very clever hacks and unrecommended programming, there is nothing you can do to change it.
What you should do in this case is change the getValue property of com.company.topLevelFunc. The way you are attempting to do that is slightly wrong and i will explain why.
a = function() { // this is not a
var c = function() { return 3; };
return { // this object is a
b : c;
}
}(); // called immediately
In this construct, a is not a function. The function you see there is invoked immediately and a is assigned the return value of that invocation. In fact this is almost equivalent:
a = { b : function() { return 3; } };
Why you would use the first construct instead of the second is a question asked many times here. A short answer is that the first allows you to have private stuff that nobody else can access (like your get method).
So a is an object with a property who's value is a function that returns 3. If you want a to return 4, you need to do something like this:
a.b = function() { return 4; }
This keeps the other properties of a intact (if it had any) and only changes the property you are interested in.
If you want b to access some private properties defined in the anonymous function above, it simply cannot be done.

Can someone explain this function-wrapping syntax in JavaScript?

I understand the concept of variable scope in the following example, but can someone explain the function-wrapping syntax (...)();, e.g. how do you use it in actually day-to-day JavaScript programming? It's not something that I know from PHP/Java/C#.
window.onload = function() {
var i = 4;
console.log(i); //4
(function showIt() {
var i = 'whatever';
console.log(i); //whatever
})();
console.log(i); //4
};
There are several ways in which this form is useful. One is to lexically scope a segment of code so that its inner variables and methods stay separate from the larger body of code that contains it. In this way, it's JavaScript's way of doing block scoping. But the most common way I use this format is as an alternative to this:
var ret = {
depth:0,
initialized:false,
helper:function() { /*help with some stuff*/ },
initialize:function(){ /*do some initialization code*/ },
action:function(){/*do the thing you want*/}
destroy:function() { /*clean up*/ }
}
The thing that absolutely kills me about this format is it is extremely time consuming to find missing braces and commas. For example, the code above won't work because the's no comma at the end of the action declaration and unless I had pointed it out, you'd have had a hard time finding the problem because when the exception is thrown, it's thrown on the entire statement, not the section that's "causing the problem". This is such a predictable problem that I simply don't use this format any more if I can possibly avoid it. I refuse. Instead, the same can be written much more clearly as:
var ret = (function(){
var self = {},
initialized = false;
var helper = function() { /*help with some stuff*/ };
self.depth = 0;
self.initialize = function() {/*do some initialization*/};
self.action = function() {/*do the thing you want*/};
self.destroy = function() { /*clean up*/ };
return self;
}());
There are two big advantages for me. One, missing braces and commas can be found more easily (when the exception is thrown, the line number will be close to the area where it's missing). And two, you can choose to keep some variables and methods private and you retain all the benefits of the first block of code.
And the last plug I'll give for this format is that the code above (which is sort of like a Singleton) can be converted into a constructor by 1) removing the invocation braces on the outside, 2) changing self = {} to self = this, and 3) optionally removing the return self at the end:
var Ret = function(){
var self = this,
initialized = false;
var helper = function() { /*help with some stuff*/ };
self.depth = 0;
self.initialize = function() {/*do some initialization*/};
self.action = function() {/*do the thing you want*/};
self.destroy = function() { /*clean up*/ };
return self; // this is ignored by the compiler if used as a constructor
};
var ret = new Ret();
This is defining a function showIT (using function showIT() {...}) similar to what you're already familiar with. The () at the end directly invokes the function in the same line as it is defined. That's probably the part that is new to you. Just like you'd say showIT() to invoke the function, you can replace the name with the actual definition and it'll work in Javascript.
JavaScript has function literals. All it's doing is making a function literal, and calling the result of the expression. Is the name what's confusing you? All a name would be used for is referring to the function inside its own body, and it's optional. (Note that that's not compatible with IE 8 and earlier.)
Unlike in C where variable names have block scope, JavaScript (like Pico) has only function scope.
So if you want to create a new name scope you can't just use { ... } as you could in C, you have to use (function() { ... })();.

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