Unexpected behaviours while invoking methods in Javascript ES6 classes - javascript

Primarily I'm a C# developer learning Javascript of late. I was trying out ES6 classes. I expected ES6 classes to behave like regular classes, but finding many anomalies.
class Test{
constructor(){
console.log("Constructor Invoked");
}
instanceMethod1(){
console.log("instanceMethod1 Invoked");
}
instanceMethod2InvokesInstanceMethod1(){
console.log("instanceMethod2InvokesInstanceMethod1 Invoked");
this.instanceMethod1();
//instanceMethod1(); //wont work in JS, but will work in C#
}
instanceMethod3InvokesStaticMethod1(){
console.log("instanceMethod3InvokesStaticMethod1 Invoked");
Test.staticMethod1();
//staticMethod1(); //Wont work in JS, but will work in C#
}
static staticMethod1(){
console.log("staticMethod1 Invoked");
}
static staticMethod2InvokingStaticMethod1(){
console.log("staticMethod2InvokingStaticMethod1 Invoked");
this.staticMethod1();
Test.staticMethod1();
//staticMethod1(); //Wont work in JS, but will work in C#
}
static staticMethod3InvokingInstanceMethod1(){
console.log("staticMethod3InvokingInstanceMethod1 Invoked");
new Test().instanceMethod1();
//this.instanceMethod1(); //wont work
}
}
var ob = new Test();
ob.instanceMethod1();
ob.instanceMethod2InvokesInstanceMethod1();
ob.instanceMethod3InvokesStaticMethod1();
Test.staticMethod1();
Test.staticMethod2InvokingStaticMethod1();
Test.staticMethod3InvokingInstanceMethod1();
My Questions:
Inside instanceMethod2InvokesInstanceMethod1 - Why calling instanceMethod1() wont work? Instance methods can't be invoked without an instance and hence calling an instance method within an instance method should make sense right?
Inside instanceMethod3InvokesStaticMethod1 - Test.staticMethod1() will work is fair enough. But why cant we directly call staticMethod1 ?
Inside staticMethod2InvokingStaticMethod1 - How this.staticMethod1() works ? What is the this object here ?
Inside a static method, this.staticMethod1() works, but not this.instanceMethod1(). Why ? I guess answer to question 3, should help answer this question.
Could someone please help me here.

Your first problem is assuming that Javascript behaves like C++. There are some similarities, but many differences. You should not immediately EXPECT that something that works in C++ will work in Javascript. They are not the same language and this is a common problem when C++ developers start learning Javascript (it happened to me too).
Inside instanceMethod2InvokesInstanceMethod1 - Why calling instanceMethod1() wont work? Instance methods can't be invoked without an instance and hence calling an instance method within an instance method should make sense right?
No, Javascript is not C++ and does not offer that feature. You must use an object prefix when calling a method, even inside a method of that object.
Inside instanceMethod3InvokesStaticMethod1 - Test.staticMethod1() will work is fair enough. But why cant we directly call staticMethod1 ?
Again, not a feature of Javascript.
Inside staticMethod2InvokingStaticMethod1 - How this.staticMethod1() works ? What is the this object here ?
You will need to learn the rules for how Javascript sets the value of this. It is generally set based on how the method is called (though there are some ways to supercede that (like with arrow functions). See Six ways this gets set for reference info.
In this specific question, because you called staticMethod2InvokingStaticMethod1 like this: Test.staticMethod2InvokingStaticMethod1();, the this pointer inside that function will be set to Test which means you can then call other static methods of Test by reference this.someOtherStaticMethod(). This is the most basic rule for how this is set. If you call obj.method(), then inside of method, the this pointer will be set to obj.
What is important to realize in Javascript is that a method is just an ordinary function that happens to be a property of some other object. It has no particularly binding to any instance. It only gets a binding to an instance when such a binding is specified in how the method is called. The one exception to this is arrow functions which are not used for methods. In those cases, a function can be declared with the arrow syntax and it's this value will be set to the lexical value of this at the point of declaration. If you're just starting to learn this, I'd suggest you skip arrow functions until you have everything else about this firmly in your grasp. They were not part of the language until a couple years ago so you can write perfectly fine Javascript without them (they are mostly a syntax shortcut for some purposes).
Inside a static method, this.staticMethod1() works, but not this.instanceMethod1(). Why ? I guess answer to question 3, should help answer this question.
Yes, as you expected, same answer as 3.

Related

what does function () {} mean when assigned to a variable

I know that functions are objects in javascript, and that functions can be assigned to variables. I am also aware of this question: How does the (function() {})() construct work and why do people use it?.
But I would like to know precisely what does it mean in this context:
https://github.com/zsolt/retwis-nodejs/blob/master/domain.js#L43
User = function(){}
This line is followed by the declaration of some member functions (methods?) of the "supposed" User object.
It seems there is no other explanation answer here in SO.
It means User is a function that takes no inputs, has no side effects and returns nothing.
Most likely it is a class constructor and methods will be added to it later. User.foo = function() { /* ... */} would imply a static method, so this is more like a utilities class if you're used to thinking in Java architecture.
You should look up pseudo-classical inheritance in Javascript. Analogizing to Java, the code would be adding static methods to the User class, not object.
I'm still pretty convinced the code is following Java class patterns because the writer would prefer User to be a constructor that can be instantiated, has static methods, and has no instance methods (that I saw), over an object with properties that are functions. You are right that this is circuitous, but it's what the writer would do if they are a Java developer. It does have the advantage that instance methods may be added to User later with little client-code impact but I see no evidence this will happen to User (I didn't look long).
By the way, I deduced this because CapitalizedNames for functions implies it should be called with new in Javascript engineering in general, which implies it's a class. Figuring out why a class might be preferable just has to do with Java experience.
The canonical way to create an object in Javascript is:
function user(config) {
this.config = config;
...
}
User = new user(config);
It uses this context (and concept). This format is used if you want to create named properties and/or methods.
If you don't need to create this context you may use just following:
User = function(){}
Here the constructor function is anonymous and doesn't create any context. For the same reason the new keyword is not needed.

What is a proper, modern and cross-browser safe method of creating JavaScript classes?

I am confused with hundreds of ways of creating JS classes. One says that I should use prototypes, while others say that noone uses prototype beacuse it is "bad". On the other hand CoffeeScript uses prototypes but wraps a construction with a function whick returns itself (or something). I've seen function that returns an object, function that returns a function that returns an object etc..
I think it should be easy and no frameworks should be needed to create classes in a language - maybe I'm missing something.
There are also two (al least) ways of creating methods : foo: function() {} and function foo() {}. I've even seen those two ways in single class. The problem is that the first way results in creating annonymous functions (wich happens to be assigned to a field of an object) and debuggers say that error happened in annonymous function called by annonymous function etc.
I understand that JS is intended to be functional rather than OOP, but sometimes a class is the best way to describe a concept (e.g. a UI widget wants to be a class).
I'd be grateful for an example of proper constructed class with few words of explanation.
I think this article explains it well:
https://developer.mozilla.org/en-US/docs/JavaScript/Introduction_to_Object-Oriented_JavaScript
This is (I believe) the correct way to use classes in a prototype based language like javascript, and gives a good explanation of the concepts. I use this approach in my projects, and it seems to work in all modern browsers.
I think you can consider the code that CoffeeScript produces "good":
// Create a "class" named Foo = create a variable that contains whatever the
// self-invoking anonymous function returns (the function avoids the pollution
// the global namespace).
var Foo = (function() {
// Create the "class" = the constructor function that is supposed to be used
// with the "new" keyword to create instances (objects).
function Foo() {}
// Add a method "bar" (that's what the prototype is for!)
Foo.prototype.bar = function(baz) {
// Assign the value to a member variable of the current instance (this)
this.foobar = baz;
};
// ...add more stuff.
// Return only the function, every other local variable stays in this scope.
return Foo;
})();
If you are confident in using CoffeeScript, it has solid approach to classes, and gives you much clear syntax, compared to any other OOP framework at the same time.

Calling a class which contains a constructor to setup click events etc?

I am trying to organize my JavaScript. What I would like to do is have a class for each PAGE rather then just entering JavaScript straight into a js - is this good practice?
Let me explain: thinking along the lines of is it a good or bad idea on my variable naming. Remember that this a kind of class so I have to create the class but then I must call it (see below). I am using the prototype and constructor pattern.
// THIS FILE WILL BE SAVED as RESERVATIONPAGE
function ReservationPage(){
// Setup click events in this constructor
$('submit-button').bind('click',this.submit_click);
$('clear-button').bind('click',this.clear_click);
// setup other variables
}
ReservationPage.prototype = {
constructor: ReservationPage,
submit_click : function () {
alert(' you just clicked the submit button');
},
clear_click : function () {
alert('button for clearning the form fields!!');
}
};
Then each page will need a standard js file i.e. not a class / object to instantiate their Page js like above, so a kind of entry point - so hence:
// THIS FILE WILL BE SAVED as ReservationLoad - notice the word Load :-) -- don't know if this is good naning convetion, anybody suggest anything different??
var reservationPage = new ReservationPage(); // CREATES NEW INSTANCE OF THE CLASS/OBJECT ..
I don't any other way of doing it; I would really appreciate any input. I will be using jQuery extensively but this shouldn't matter. I need a standard JS file - no objects to instantiate my objects hence I called in load. This in turn instantiates the object and calls the constructor.
The constructor sets up the click events and then calls the methods.
Is this good?
Any idea where I am going wrong?
I really appreciate some input as I am little lost and want to do it right. I am coming from a C# .NET background, and I know js isn't a proper OOP language but I am trying to treat it like this for better structuring.
This way, all my js files are separate from my HTML and my CSS; there are no events entered into the html, they are all entered via code
Look forward to any info
JavaScript is a proper OOP language. It's not class-based like you're used to (it's prototype-based), but it is absolutely object-oriented -- very much so.
You can simulate classes and class-based inheritance in JavaScript (it's that powerful), which can be useful for people like you (and me) with backgrounds in that world. But classes are not the only way to modularize, which is really what you're talking about doing.
The solution presented in your question creates a function backed by an object (the prototype) which you can then use to create another object (the instance) that then does what you want. That fits the class-based mindset (which may be a good enough reason to do it!), and it's what I do for things I may need to create more than one of, but in some sense it may be overkill for this purpose, since you're not going to have multiple instances of your page objects at any given time. It also means that your click handlers won't work as defined in your example code -- when they're called in response to a click, the this value will be wrong, it won't point to your ReservationPage instance. (Functions in JavaScript are just functions, they're not methods; this is defined by how the function is called, not how it's defined. Surprising to people like us, but it turns out that it's incredibly useful.) That can be worked around, of course, but it requires...working around it.
Since you're only going to need one instantiated object for the page, rather than all the hassle of constructor functions and prototypes such, why not just have one object for the page? And you can use a closure (function) to put scope around that object so it can have easily-accessed variables without having to worry about this and without polluting the global namespace. Here's an example of doing that:
// Create a closure (function) to scope our variables, assign its
// return value to a variable for our page
var reservationPage = (function() {
var somePageData; // A private variable for our page
// Our load function; we'll export that below
function onLoad() {
// Hook some elements
$('submit-button').bind('click', submit_click);
$('clear-button').bind('click', clear_click);
// Set up some page data
somePageData = 42;
}
// A private function for handling the click of the submit button
function submit_click() {
alert('You just clicked the submit button; page data is ' + somePageData);
}
// A private function for handling the click of the clear button
function clear_click() {
alert('You just clicked the clear button; page data is ' + somePageData);
}
// Export any functions we may need outside the closure
return {onLoad: onLoad};
})();
$(document).ready(reservationPage.onLoad);
Note that all of the functions have access to the somePageData variable, and to each other, but we didn't have to worry about this. That's because the functions are declared within the scope in which the somePageData is declared, and so they "close over" it (have access to it). That access is "live", it's not a copy or something.
Note that I've wrapped the entire thing in a function. I'm doing that because we want to avoid just dumping everything in the global namespace, because A) it's the Right Thing(tm), and B) you're combining all of your pages into one file you reuse. You could have four or five (or 20) page objects in your combined file, all definining a var with that same name, and they'd be kept distinct because they're declared inside separate functions. Similarly, the functions for the page (onLoad and the like) are scoped to the function. Using a scoping function like this is called the "module pattern."
I also didn't bother to export any more than I had to make public (just the onLoad function). There's no need for our handlers to be available outside the closure.
Another aspect of the above that can be useful: All of the functions we care about have names. Named functions help tools help you, by telling you where an exception occurred, etc. There's a big difference, from a tool's point of view, between an anonymous function assigned to a variable:
var fname = function() { /* ... */ };
...and a named function:
function fname() { /* ... */ };
This is just a side-note, though; you can do that with the code in your question, too:
ReservationPage.prototype = (function(){
function submit_click() {
alert(' you just clicked the submit button');
}
function clear_click() {
alert('button for clearning the form fields!!');
}
return {
constructor: ReservationPage,
submit_click: submit_click,
clear_click: clear_click
};
})();
Now, I wouldn't use the "one object" pattern for anything general purpose that I might want more than one of; that's what classes (or things like classes) are for. Hence the links above to simulating classes and solving the this problem. :-) But for modularizing and organizing the script that's specific to the page, classes may be overkill.

common reasons for javascript reference error with prototype

I am new to the prototype framework and fairly new to Javascript (it's been a long while sicne any heavy javascript work). I have defined a class that is calling another method within it and I keep getting a ReferenceError "getLabel is not defined". getLabel is another class method that I am trying to call. Here is the code where I am calling it:
var title = new Element('td');
title.addClassName(label_class);
title.addClassName('scorecard_tee_title');
title.appendChild(new Element('span').update(getLabel(tee, true)));
I have tried using this.getLabel as well but to no avail. I'm guessing that I have a syntax error in my class (which is too large to place here), but can't find what's wrong.
What should I be checking for? Are there any common reasons for this error to be thrown that I should keep in mind when using Prototype?
Thanks!
UPDATE: I pulled the getLabel function out of my class and it works fine, which leads me to believe that it is in some way related to the getLabel function being passed into or evaluated as a member of the class and not a standalone function. Still not sure what I'm doing wrong though.
It is my understanding (which I admit, is pretty limited when it comes to object oriented programming), that you don't call methods as functions directly. They need to be called as methods for an object. For instance:
getLabel(foo);
If getLabel is method of a class, it modifies an object. In your example, you are not modifying an object, so what is getLabel actually getting the label for? If it's getting the label of tee, then you'd want:
tee.getLabel();
But if I'm wrong, somebody let me know and I'll delete this.
You need to reference getLabel somehow, either classInstance.getLabel() or this.getLabel(). I see you already tried the later so I'm assuming this code is not running inside the same class as getLabel() belongs to?
The problem with the undefined methods was being caused because the method that was calling them were being called from anonymous function. Binding the anonymous function to (this) from where it was being created works.
I realized this when I looked at 'this' in Firebug and realized it was pointing to Window and not Object.

How to Implement Closures Using SpiderMonkey API?

I've been working with the SpiderMonkey C API and would like to implement a closure in C using their API. The one I would like to implement is fairly complex, but I can't even figure out how to do a simple one such as:
function x() {
var i = 0;
return function() { i++; print(i); };
}
var y = x();
y(); //1
y(); //2
y(); //3
I was wondering if anyone knows how I might do this. I found the JS_NewFunction method, but I don't actually know if that is a step in the right direction. Any help will be appreciated, thanks!
I don't know if there's a pure C way of doing closures or not. I would reccomend though, if you can, to just implement the functionality you need in javascript, and simply evaluate the javascript text in JSAPI. From there, use JSAPI to grab whatever handles/variables you need to implement your host functionality. It's really onerous to do javascripty things using JSAPI, avoid it if you can.
Narrated as if you're probably still interested, a year later.
Knitting my brows furiously at the documentation for JS_GetParent, I see
For some functions, it is used to implement lexical scoping (but this is an implementation detail).
and then, along with a list of API functions that create functions,
Some of these functions allow the application to specify a parent object. If the JSAPI function creating the object has a parent parameter, and the application passes a non-null value to it, then that object becomes the new object's parent. Otherwise, if the context is running any scripts or functions, a default parent object is selected based on those.
I might experiment with this later, but it seems that you might be able to do this either by (merely) creating the function in the API during the execution of the function that you want it to have the scope of.
Otherwise, you might be able to set the lexical scope of a function to some object manually using JS_SetParent, but the documentation keeps ominously calling that use of parents 'internal'.
</necro>

Categories

Resources