I wrote a JS simple class:
// JS simple class
class myClass
{
constructor(init=0) { this.var = init; }
add(n) { this.var+=n; return this; }
sub(n) { this.var-=n; return this; }
}
The class can be used with method chaining:
// Works well
obj1 = new myClass(0);
obj1.add(5);
obj1.sub(2);
console.log (obj1.var);
// Method chaining, works well
obj2 = new myClass(0);
obj2.add(9).sub(4).add(3);
console.log (obj2.var);
I would like to create a closure for convenience, thus the class could be used without explicitly creating a new object. For example, I would like something like:
obj(0).add(5).sub(2);
When calling obj(0), a new instance of the class is created. I wrote the following closure, but the following does not work:
// Closure instantiating the class
var obj = function(init)
{
var obj = new myClass(init)
return { add:this.add, sub:this.sub };
}
When calling obj(0).add(3);, the following error is displayed in the console:
Uncaught TypeError: obj(...).add is not a function at window.onload ((index):58)
I don't know how to do this, and I'm even not sure the closure is the right tool.
Note that I already have a working solution without class (with closures), but I would like to keep my class.
I made a JSFiddle here
Your fonction should return the new object:
// Closure instantiating the class
var obj = function(init)
{
return new myClass(init);
}
I updated the fiddle : https://jsfiddle.net/48mr2t5y/
Related
Class Example:
$(document).ready(function(){
var $ = function(id)
{
return document.getElementById(id);
}
class someClass
{
constructor()
{
...
}
someMethod()
{
...
}
}
... // rest of examples within this scope
});
So far I am able to create an instance of the class object when the window loads and then calling a method of that class on a button click event while also binding this:
var obj = new someClass()
$('startButton').onclick = obj.someMethod.bind(obj)
All works fine and well until I want reset by deleting and creating a new instance of that class object. I have attempted a couple of different methods:
First, I attempted to call a function on button click that does one more task than before (instantiates a new object). I tried this both with declaring the variable obj in the global scope specifying var for the type and assigning it to null, and then attempted to re-assign it and bind this on button click. This works up until I attempt to call my setup() method:
$('startButton').onclick = function() {
var obj = new someClass();
var obj.setup.bind(obj); // fails to call
}
I then attempted another route, which more or less landed me in the same spot:
$('startButton').addEventListener('click', function(event) {
var obj = new someClass();
console.log('obj is an instance of someClass?', obj instanceof someClass); // returns true
obj.setup.bind(obj); // fails to call
});
Without creating a new method within someClass that manually resets all of my class attributes back to the initial values (I'd rather re-call the constructor), how can I gracefully instantiate a new class object on button click and be able to bind this?
And when I do, is it okay to re-assign the variable holding the class object without first marking it for GC or deallocating it somehow? Nothing else references it. Apologies in advance if my terminology is off, I'm new to this.
obj.setup.bind(obj) binds a context to a function, but it does not call it. You either need to call it:
obj.setup.bind(obj)();
Or use .call() instead of .bind():
obj.setup.call(obj);
However in this case, since you call the method directly on the instance, there is not really a need to bind anything:
$(document).ready(function() {
var $ = document.getElementById.bind(document); // <-- bind without calling
class someClass {
constructor() {
this.ready = false;
}
setup() {
this.ready = true;
}
}
$('startButton').addEventListener('click', function(event) {
var obj = new someClass();
obj.setup();
console.log(obj.ready); // true
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<button id="startButton">Start</button>
I'm experimenting with javascript. I'm trying to make a "class" but it is not working like it should. I have problems initiating a new instance of MyClass. See the js fiddle. Is it possible to add a constructor to MyClass just like in php?
I'm also not sure that this is the way "classes" are defined in javascript. So any help is more then appreciated.
http://jsfiddle.net/kasperfish/JnvFS/
var MyClass={
test:'hello',
hallo: function(){
alert(this.test);
},
setTest: function(x){
this.test=x;
}
}
MyClass.hallo();
MyClass.setTest('world');
MyClass.hallo();
//not working because MyClass is/does not have a constructor
x= new MyClass;//*
x.hallo();
* firebug: TypeError: MyClass is not a constructor
In JavaScript, the constructor of a class is just a function, and the members are set either in there, or using the prototype object. For example:
function MyClass(someArgument) {
// construction, init members of this
this.someField = someArgument;
this.test = 'a test';
}
// in addition, all members of `prototype` are automatically set on every
// new instance of MyClass.
MyClass.prototype.hallo = function(){
alert(this.test);
};
and then
var inst = new MyClass(42);
inst.hallo();
I suggest you read up on prototype-based OOP in JavaScript. It is definitely different than the one you may be used to from PHP, and it generally does not feel very intuitive.
You're gonna have to make your MyClass Object a function like this:
var MyClass = function() {
this.test = 'Hello';
};
MyClass.prototype.hello = function() {
alert(this.test);
};
MyClass.prototype.setTest = function( x ) {
this.test = x;
};
var myInstance = new MyClass();
myInstance.hello();
myInstance.setTest('World');
myInstance.hello();
ok, firstly you should know that javascript does not have "classes" per say, javascript datastructures are indeed made of objects but as you can see from your code above, objects are essentially key-value pairs much unlike other languages like php, the implementation of OOP in javascript is very different.
if you would like to use a constructor to create instances of your object, then try and create your "class" using a function, a construtor, maybe in this way:
function MyClass(){
this.test ='hello';
this.hallo = function(){
alert(this.test);
};
this.setTest = function(x){
this.test=x;
};
}
var myClassInstance = new MyClass();
myClassInstance.hallo();
myClassInstance.setTest('world');
myClassInstance.hallo();
i hope this helps
Ok I should know the answer to this but for some reason I have never really understood or had the need to really get to know JavaScript.
My question is: Looking at the code samples below am I correct in my understanding or am I missing some information.
Sample 1
Need to instantiate the function (or class) in order to use the IsOld method, and a separate copy of the IsOld function will be created for each instance.
function MyClass1() {
this.IsOld = function (age) {
if (age > 40) {
return true;
}
return false;
};
}
// sample usage
var m1 = new MyClass1();
console.log(m1.IsOld(34));
Sample 2
Need to instantiate but unlike MyClass1 the scripting engine will not need to create a copy of the method IsOld for each class instance.
var MyClass2 = (function () {
function MyClass2() { }
MyClass2.prototype.IsOld = function (age) {
if (age > 40) {
return true;
}
return false;
};
return MyClass2;
})();
// sample usage
var m2 = new MyClass2();
console.log(m2.IsOld(34));
Sample 3
No need to instantiate the function / class to access the IsOld method. A single instance of the IsOld method is used across all invocations.
var MyClass3 = {
IsOld: function (age) {
if (age > 40) {
return true;
}
return false;
},
};
// sample uage
console.log(MyClass3.IsOld(34));
Note: I am guessing there are plenty of similar question / answers here on SO but for some reason I could not find one that actually made sense to me.
Your understandings seems to be correct.
If by "need to instantiate" you mean use of 'new' keyword, I'd like to add something here.
In JavaScript use of new keyword is not the only way to create new instances. (Edited as per comments)
And any function can act as a constructor function.
When you use 'new' keyword followed by any function (say 'x') what it does is
Create new object (say 'y'), and set the function x's prototype as the new objects (y's) prototype.
Call the function 'x' in the newly created objects y's context, i.e this would refer to this new object 'y' inside the function 'x'
If the function does not return an object, return the new object 'x' created by the new operator as the result of the new expression.
Here is a good source for you to learn JavaScript by Douglas Crockford (http://javascript.crockford.com/)
So, if you are concerned about the memory (you should be), use a constructor function, and add all the common methods to functions prototype like you have done in Sample 2.
Then all those methods will be inherited to all the objects created using this function as the constructor. However, as mentioned before I think Sample 2 can be simpler:
var MyClass2 = function MyClass2() { };
MyClass2.prototype.IsOld = function (age) {
if (age > 40) {
return true;
}
return false;
};
var obj = new MyClass2();
As far as I know, you're right in all 3 cases.
Does need instantiate IsOld and for every instance there will be new function created.
Doesn't need instantiate IsOld as it is in prototype.
Doesn't need instantiate IsOld as MyClass3 is already an instance (an object not a function).
It seems to me there's been some misunderstanding regarding to the structure of the class and the dynamic nature of Javascript: for all the presented cases, every instance of the "class" creates a new unnamed function.
If you want to declare "classes" in a more traditional way (like C++ or Java), you'd better:
1) Define the functions:
function MyClass_IsOld(age) {
return (age > 40);
}
2) Create the "class" and define its prototype:
function MyClass() { /* put any instance constructor logic here */ };
MyClass.prototype.IsOld = MyClass_IsOld;
3) Use the class:
var myInstance = new MyClass();
console.log(myInstance.IsOld(37));
If you want to use the "method" as a regular function, declare it globally, like:
function MyClass_IsOld(age) {
return (age > 40);
}
function MyClass() { /* put any instance constructor logic here */ };
MyClass.prototype.IsOld = MyClass_IsOld;
var myInstance = new MyClass();
console.log(myInstance.IsOld(37)); // use as a method
console.log(MyClass_IsOld(37)); // use as a function
If you want to hide the implementation details, create a closure:
var MyClass = (function () {
function _MyClass_IsOld(age) {
return (age > 40);
}
function _MyClass() { /* put any instance constructor logic here */ };
_MyClass.prototype.IsOld = _MyClass_IsOld; // use as a method
return _MyClass;
})();
var myInstance = new MyClass();
console.log(myInstance.IsOld(37)); // use as a method
console.log(MyClass_IsOld(37)); // ERROR: undefined function
If I create a constructor function BlahWidget and give it 2 public methods: publicHello and secondHello. I assign publicHello directly inside the widget using 'this' but use the prototype object to assign the secondHello method, what difference does that really make to the behaviour of the 2 methods on the widget?
var BlahWidget = function(){
this.publicHello = function(){
alert("Hello");
}
};
BlahWidget.prototype.secondHello = function(){
alert("Second Hello");
}
My understanding was that using .prototype allows it to be called by inherited objects. But turns out that this is not the case. Both methods can be called by the inherited function objects, as shown below:
var MiniBlah = function(){
this.callSupers = function(){
this.publicHello();
this.secondHello();
}
}
MiniBlah.prototype = new BlahWidget();
MiniBlah.prototype.constructor = MiniBlah;
var x = new MiniBlah();
x.callSupers();//calls both publicHello and secondHello
The difference is that functions declared on the prototype object are shared across instances of objects created by a constructor function whereas functions declared inside of the body of a constructor function are not, they belong to the object constructed from the function.
What this means in practice is that you could create a load of objects from a constructor function with a function on the prototype doing X, then change that function on the prototype to do Y and all object instances will get the new functionality of the function.
An example
var BlahWidget = function(){
this.publicHello = function(){
console.log("Hello");
}
};
BlahWidget.prototype.secondHello = function(){
console.log("Second Hello");
}
var blah1 = new BlahWidget();
var blah2 = new BlahWidget();
blah2.publicHello = function() {
console.log("Goodbye");
}
blah1.secondHello(); // logs SecondHello
blah2.secondHello(); // logs SecondHello
BlahWidget.prototype.secondHello = function(){
console.log("Second Goodbye");
}
blah1.secondHello(); // logs Second Goodbye
blah2.secondHello(); // logs Second Goodbye
blah1.publicHello(); // logs Hello
blah2.publicHello(); // logs Goodbye
Every single instance of "BlahWidget" will have its own distinct copy of the "publicHello" function.
Also, though this is just academic, I'm not sure I'd say that "prototype" is a keyword; it's more like a "special property name".
In JavaScript Functions are so powerful to build OOPs and modular concepts. Following concepts are implemented using Function only in JavaScript:
Method
Class
Constructor
Module
Below code shows the code which create class MyClass and it has private members:
function MyClass(a) {
var count = 3; // private member
// this check function is private function
function check() {
if (count > 0) {
count--;
return true;
}
else {
return false;
}
}
this._a = a;
this.get = function () {
if (check()) { // use of private function
return this._a;
}
else {
return "Thullu"; // after invoking get method 3 times in the object this else will be executed
}
}
}
In the above code variable, count is private as any object created from MyClass will not have this variable similarly function check() is private function as this function is not part of this in the MyClass. When we create an object of MyClass using new keyword this is returned. This concept is possible in JavaScript because of lexical scoping (functional scoping).
When we create object of this class MyClass, and call the get method more than 3 times:
I would like to write few points regarding new keyword.
When a function is called with the new operator, a new object is created with prototype members and assigned to this.
Above statement is true only if there is no explicit return value in the function. If explicit return is present in Class (function), then same return will be assigned to the object.
I would like to give here one more example with very basic functionality like in all OOP languages we have. We declare private field and then use public properties to expose the private field, in more formal and OOPs way we create Get and Set method to update private field or retrieve private member of class.
Same get and set functionality for private variables in JavaScript we can achieve as shown in below example:
// private class with get and set methods
function MyClass() {
var _privateField = 0; // It is private field as it is not part of "this"
this.GetPrivateField = function () {
return _privateField;
};
this.SetPrivateField = function (value) {
_privateField = value;
};
}
I try to create some class based-on jQuery style like the following code.
myClass = window.myClass = function(x, y)
{
return new myClass.fn.init(x, y);
};
myClass.fn = myClass.prototype =
{
init: function(x, y)
{
// logic for creating new myClass object.
}
};
I do not understand why jQuery use new keyword for creating its class because from my experiment, JavaScript always create myClass.init object instead of myClass object. However, I try to remove new keyword in myClass constructor. But it still not changes. Can you explain why jQuery can do that but I can’t or give me some code for using in init function?
By the way, I can use the following code instead of jQuery style code for creating the same object. What is the different between my code & jQuery code? Are there any benefit for using jQuery style?
myClass = window.myClass = function(x, y)
{
this.init(x, y);
};
myClass.fn = myClass.prototype =
{
init: function(x, y)
{
this.x = x;
this.y = y;
}
};
PS. I like write code that separate initial logic into function because it is very easy to override this function by other people that use my code like my following code.
// override init function of myClass
myClass.fn._old_init = myClass.fn.init;
myClass.fn.init = function()
{
// logic for doing something before init
this._old_init();
// logic for doing something after init
};
Thanks,
This approach should work perfectly. One thing you may be missing is the fact that, using this technique, you're not going to be creating an instance of myClass; you're going to be creating an instance of myClass.prototype.init.
So, any methods defined in myClass.prototype won't be available to the instance. You'll want to make sure that the init's prototype points to myClass's prototype:
myClass.fn.init.prototype = myClass.fn;
FWIW, I don't see any real benefit in this approach. What's wrong with this? -
function myClass(x,y) {
if ( !(this instanceof myClass) ) {
return new myClass(x,y);
}
// Prepare instance
}
myClass.prototype = { /* Methods */ };
// It can still be overwritten:
var oldMyClass = myClass;
function myClass(x,y) {
// Hack some stuff here...
return new oldMyClass(x,y);
}
The jQuery object initialization should like the following code.
jQuery = window.jQuery = window.$ = function (x, y)
{
return new jQuery.fn.init(x, y);
};
jQuery.fn = jQuery.prototype =
{
init: function()
{
// some logic for object initialization
return this;
}
};
jQuery.fn.init.prototype = jQuery.fn;
The only one benefit of this code is it always create instance of jQuery object although you do not use new keyword for creating object.
In the other hand, my code that use init function for initialization object does not work if you do not use new keyword when call it. For fixing it, you must add some code like "J-P" example for checking this object. If type of it is not current class, it will automatically create instance for it.
Both of codes should work fine. But I like jQuery style more than "J-P" style because it is quite easy to read and modify.
Thanks,
I'm not entirely sure what the question is, but I'll do my best to answer what I think you're asking.
the new keyword is used to instantiate a new instance of the object returned by the function defined by the init property on the function prototype.
I believe the code is written in this fashion so that the new keyword is not required each time you instantiate a new jQuery object and also to delegate the logic behind the object construction to the prototype. The former I believe is to make the library cleaner to use and the latter to keep the initialisation logic cleanly in one place and allow init to be recursively called to construct and return an object that correctly matches the passed arguments.
Your second block of code does not return an object. Try it out in Firebug with
var myClass1 = myClass(1,2);
console.log(myClass1);
you get this.init is not a function error. The only way that this would work is if you use the new keyword as in
var myClass1 = new myClass(1,2);
console.log(myClass1);
Compare that with the code similar to that in jQuery
myClass = window.myClass = function(x, y)
{
return new myClass.fn.init(x, y);
};
myClass.fn = myClass.prototype =
{
init: function(x, y)
{
this.x = x;
this.y = y;
}
};
var myClass1 = myClass(1,2);
console.log(myClass1);
var myClass2 = new myClass(1,2);
console.log(myClass2);
In each case, you correctly get an object returned with an x property with value 1 and a y property with value 2, whether the new keyword is used or not.