I am trying to achieve something like the following using OO JavaScript:
class Sample
{
public int x {get; set;}
public int y {get; set;}
public int z
{
get {return x+y;}
}
}
I could not understand on how to implement property 'z' in above class.
You have to use a function. As of ECMAScript 5th edition (ES5), that function can be a "getter" for a property that you access in the normal non-function way; prior to that you have to use an explicit function call.
Here's the ES5 way, using defineProperty: Live copy | source
function Sample()
{
// Optionally set this.x and this.y here
// Define the z property
Object.defineProperty(this, "z", {
get: function() {
return this.x + this.y;
}
});
}
Usage:
var s = new Sample();
s.x = 3;
s.y = 4;
console.log(s.z); // "7"
With ES3 (e.g., earlier versions):
function Sample()
{
// Optionally set this.x and this.y here
}
Sample.prototype.getZ = function() {
return this.x + this.y;
};
Usage:
var s = new Sample();
s.x = 3;
s.y = 4;
console.log(s.getZ()); // "7"
Note that you have to actually make the function call getZ(), whereas ES5 makes it possible to make it a property access (just z).
Note that JavaScript doesn't (yet) have a class feature (although it's a reserved word and one is coming). You can do classes of objects via constructor functions and prototypes, as JavaScript is a prototypical language. (Well, it's a bit of a hybrid.) If you start getting into hierarchies, there starts to be some important, repetitive plumbing. See this other answer here on Stack Overflow for more about that.
Related
I have a JS plugin using es6 class syntax. I'm not sure on the way to handle several instances of the class versus once instance with a several element inside.
This plugin can have an array an unlimited number of image nodes as parameters.
This is the class syntax I have so far
(function(window) {
function handle(element, options) {
let handles = [];
if (element.length) {
for (var i = 0; i < element.length; i++) {
handles.push(new Plugin(element[i], options));
}
} else {
handles.push(new Plugin(element, options));
}
return handles;
}
class Plugin {
constructor(element, options) {
this.element = element;
this.init();
}
init() {
//get its translated value
this.methodA();
//apply its translation even if not visible for the first init
this.methodB();
}
methodA() {
this.element.classList.add('test');
}
}
return handle;
});
I would like to get rid of this handle function. What is the other way to have an instance of plugin for every element? and to be able to have the classPlugin at the top level without the need for this handle function.
I don't see any other way that having several instances of the class, because each instance get specified info for each image (height, offset, etc). Maybe I am missing something obvious here...
You can't actually instantiate an instance of a class without a loop. You may try eval. But it's not recommended. It's a bad practice.
Now let me explain why it is not possible.
JavaScript does not have classes and instances, it has only objects, which can delegate to other objects.
To create two objects based on a single object, but behind the scenes, there aren’t really two ‘instances’ of the Point object, there are just two objects that delegate to the original one. When you use new, JavaScript is actually just creating an object and setting its prototype to the object returned by the constructor function. Imagine if the example had been expanded to include a shared method like this:
function Point(x, y) {
this.x = x;
this.y = y;
}
Point.prototype.logCoords = function () {
console.log(this.x, this.y);
};
var a = new Point(1, 2);
console.log(a.x); // logs '1'
a.logCoords(); // logs '1 2'
Behind the scenes, what’s happening is something more like this:
var Point = function (x, y) {
this.x = x;
this.y = y;
};
Point.prototype.logCoords = function () {
console.log(this.x, this.y);
};
var a = {};
a.__proto__ = Point.prototype; // see note below about this
a.constructor = Point;
a.constructor(1, 2);
console.log(a.x); // logs '1'
a.logCoords(); // logs '1 2'
See how x and y are declared in constructor:
class Point {
constructor(x, y) {
this.x = x;
this.y = y;
}
toString() {
return '(' + this.x + ', ' + this.y + ')';
}
}
is there an way to declare properties outside of functions for instance:
class Point {
// Declare static class property here
// a: 22
constructor(x, y) {
this.x = x;
this.y = y;
}
toString() {
return '(' + this.x + ', ' + this.y + ')';
}
}
So I want to assign a to 22 but I am unsure if i can do it outside the constructor but still inside the class..
Initializing properties directly on a class in ES6 is not possible, only methods can currently be declared in this way. Same rules stand in ES7 as well.
However, it is a proposed feature that might come after ES7 (currently in stage 3). Here is the official proposal.
Additionally, the syntax the proposal is suggesting is slightly different (= instead of :):
class Point {
// Declare class property
a = 22
// Declare class static property
static b = 33
}
If you are using Babel, you can use the stage 3 settings to enable this feature.
Here's a Babel REPL example
The other way to do this in ES6, other than in the constructor, is to do it after the class definition:
class Point {
// ...
}
// Declare class property
Point.prototype.a = 22;
// Declare class static property
Point.b = 33;
Here's a good SO Thread diving into this topic some more
Note:
As Bergi mentioned in the comments, the suggested syntax:
class Point {
// Declare class property
a = 22
}
is just syntactic sugar to provide a shortcut for this code:
class Point {
constructor() {
this.a = 22;
}
}
Where both of those statements assign a property to an instance.
However, this isn't exactly the same as assigning to the prototype:
class Point {
constructor() {
this.a = 22; // this becomes a property directly on the instance
}
}
Point.prototype.b = 33; // this becomes a property on the prototype
Both would still be available via an instance:
var point = new Point();
p.a // 22
p.b // 33
But getting b would require going up the prototype chain while a is available directly on the object.
#nem035 is right that it is in proposal stage.
However, #nem035's sugggetion is one way to achieve it as class instance member.
// Declare static class property here
Seems you are looking to declare a static member. If yes,
JavaScript way is
class Point {
// ...
}
Point.a = '22';
The way you are actually expecting can be done in TypeScript
class Point {
static a = 22;
}
The compiled output will be same as above example
Point.a = '22';
Some time ago I was tying to understand js oop coming from many years of oop coding in several other laguages. I found it very confusing. After some months, a JS book and many articles and SO questions read, I sumarized it all in a concrete example that ilustrated the main oop concepts correctly working. Here it is:
function Operators() {
//mandatory
var self = this
//private
var IPT_X = '#x'
var IPT_Y = '#y'
//public
this.x = 0
this.y = 0
this.showOperators = function() {
//use of a private property (IPT_X) and a public property (this.x)
$(IPT_X).val(this.x)
$(IPT_Y).val(this.y)
}
this.clean = function() {
this.x = 0
this.y = 0
// call to a local public method
this.showOperators()
}
this.updateOperators = function(_x, _y) {
// use of a public property when call from
// derived class method is necessary
self.x = _x
self.y = _y
}
}
function Randomizer() {
// mandatory for derived classes
Operators.call(this)
// mandatory for overloaded methods with call to the inherited method
var parentUpdateOperators = this.updateOperators
var self = this
// private
function getRandomNumber() {
return Math.round(Math.random() * 1000)
}
// public
this.updateOperators = function(_x, _y) {
// call to inherited method of superior class
parentUpdateOperators(_x, _y)
// call to method of superior class
self.showOperators()
}
this.populateRandomNumbers = function() {
// call to public local method (this.updateOperators())
// and to a local private method (getRandomNumber())
this.updateOperators(getRandomNumber(), getRandomNumber())
}
// init
this.populateRandomNumbers()
}
// Mandatory for derived classes. Allows access to superior classes with
// more than 2 levels of inheritance ("grandfather" classes)
Randomizer.prototype = Object.create(Operators.prototype)
function Operations() {
Randomizer.call(this)
var self = this
//private
var IPT_RES = '#res'
var BTN_SUM = '#sum'
var BTN_SUBTRACT = '#subt'
var BTN_MULTIPLY = '#mult'
var BTN_DIVISION = '#div'
var BTN_CLEAN = '#clean'
var BTN_RAND = '#rand'
function calcSum() {
return self.x + self.y
}
function calcSubtraction() {
return self.x - self.y
}
function calcMultiplication() {
return self.x * self.y
}
function calcDivision() {
return self.x / self.y
}
function showRes(val) {
$(IPT_RES).val(val)
}
//public
this.sum = function() {
// call to 2 local private methods
showRes(calcSum())
}
this.subtract = function() {
showRes(calcSubtraction())
}
this.multiply = function() {
showRes(calcMultiplication())
}
this.division = function() {
showRes(calcDivision())
}
// init
$(BTN_SUM).on('click', function() { self.sum() })
$(BTN_SUBTRACT).on('click', function() { self.subtract() })
$(BTN_MULTIPLY).on('click', function() { self.multiply() })
$(BTN_DIVISION).on('click', function() { self.division() })
$(BTN_CLEAN).on('click', function() { self.clean() })
$(BTN_RAND).on('click', function() { self.populateRandomNumbers() })
}
Operations.prototype = Object.create(Randomizer.prototype)
var obj = new Operations()
and here is the necessary HTML to make it work:
X: <input id='x'>
<br>
Y: <input id='y'>
<br>
Res: <input id='res'>
<br>
<input id='sum' type='button' value='+'>
<input id='subt' type='button' value='-'>
<input id='mult' type='button' value='*'>
<input id='div' type='button' value='/'>
<input id='clean' type='button' value='C'>
<input id='rand' type='button' value='Rand'>
Here is a JSFiddle with my example working fine:
http://jsfiddle.net/vqqrf2cb/24/
Then I started to use this format in my daily work and all is working good. But now, after some months successfully using this format, I'm continuing to read about this subject and see that many people use different formats. So I'm trying to adapt the code above to the other possible formats of using objects. The ones I know are:
Format 1:
var something = (function() {
//private
foo = 111
bar = 222
function baz() {
//whatever
}
return {
// public
x : 333,
y : 444,
z : function() {
// whatever
}
}
})()
Format 2:
var something = (function() {
var obj {
foo : 111,
bar : 222,
function baz() {
//whatever
},
}
return obj
})()
Format 3:
var something = {
foo : 111,
bar : 222,
baz : function() {
//whatever
}
}
Format 4:
// define the Person Class
function Person() {}
Person.prototype.walk = function(){
alert ('I am walking!');
};
Person.prototype.sayHello = function(){
alert ('hello');
};
// define the Student class
function Student() {
// Call the parent constructor
Person.call(this);
}
// inherit Person
Student.prototype = new Person();
// correct the constructor pointer because it points to Person
Student.prototype.constructor = Student;
// replace the sayHello method
Student.prototype.sayHello = function(){
alert('hi, I am a student');
}
// add sayGoodBye method
Student.prototype.sayGoodBye = function(){
alert('goodBye');
}
And many small variations of all these formats. I'm even inclined to think the ways of doing OOP in JS tend to infinity. :D Anyway, I want to try some of the methods to find which one I find better in day-to-day work. But I couldn't convert my code to any other format in such a way to make all oop work. By 'all oop' I mean encapsulation (private and public methods and variables), inheritance, overloading with superior class call and finally class initialization (like a constructor or something).
My question is: Can somebody translate my working code to some other js object formats ? I'm specially interested in converting to Format 1 and Format 3. Other formats not included in the list are welcome also. One restriction: I don't want to use mixins. I want to use prototypes for inheritance.
I also have read about the modular pattern. How would this example be like using it ?
Corrections/Comments to my example are welcome also.
Edit:
After the answer and comments of #Robert and #NoBugs I've made an alternative example using the Module Pattern:
http://jsfiddle.net/ehe122e0/10/
JavaScript has many choices, so it confused me for quite a while, but ultimately I ended up embracing it as something new and disregarding any OOP knowledge I had.
For example, take Format 1 and 2 you described above. This isn't equal to classes in other languages, but is similar in the fact that it encapsulates some "thing" in your program. You should always wrap your code in at least one function to ensure your variables are never in the global scope to avoid conflicting names with other programmers. Look up "IIFE" for more details.
I generally create my objects that are simply there to move data amongst my application using the object literal notation.
var student = {
firstName: "Bob",
age: 20
};
And stick to prototypical inheritance if my objects will need any functions like Format 4 because it offers more flexibility.
Regardless of what format you decide to follow, an IIFE is important. And forget about the word "Class" and embrace the modular pattern, it is very similar but different. It's like trying to use Git like SVN.
Here is an example of a printModule and a module making use of it. Notice ModuleB can replace the current printModule with another one easily simply by passing a different object into moduleB. The way I use the exports variables varies depending on the person.
http://jsfiddle.net/0zuo1w4d/1/
I was wondering how I could make private variables in javascript through clojure. But still have them cloned when using Object.create.
var point = {};
(function(){
var x, y;
x = 0;
y = 0;
Object.defineProperties(point, {
"x": {
set: function (value) {
x = value;
},
get: function() {
return x;
}
},
"y": {
set: function (value) {
y = value;
},
get: function () {
return y;
}
}
});
}());
var p1 = Object.create(point);
p1.x = 100;
console.log(p1.x); // = 100
var p2 = Object.create(point);
p2.x = 200;
console.log(p2.x); //= 200
console.log(p1.x); //= 200
I got this technique from http://ejohn.org/blog/ecmascript-5-objects-and-properties/ but it got this limitation that the closure variables is the same on all Objects. I know this behaviour on javascript is supposed but how can I create true private variables?
I know this behaviour on javascript is supposed but how can I create true private variables?
You can't, there is no private in ES5. You can use ES6 private names if you want.
You can emulate ES6 private names with ES6 WeakMaps which can be shimmed in ES5. This is an expensive and ugly emulation, that's not worth the cost.
When you need to add private variables to just one object which was created with Object.create you can make this:
var parent = { x: 0 }
var son = Object.create(parent)
son.init_private = function()
{
var private = 0;
this.print_and_increment_private = function()
{
print(private++);
}
}
son.init_private()
// now we can reach parent.x, son.x, son.print_and_increment_private but not son.private
If you want you can even avoid unnecessary public function init_private like this:
(function()
{
var private = 0;
this.print_and_increment = function()
{
print(private++);
}
}
).call(son)
Bad thing is that you could not append private members with several calls. The good thing is that this method is quite intuitive in my opinion.
This code was tested with Rhino 1.7 release 3 2013 01 27
In Javascript I would like to create two classes: A node, and a node list. A node contains some trivial properties; a node list contains pointers to a node, and multiple node lists can contain the same nodes. Would the following be correct (simplistic) design?
function Node(name, x, y) {
this.name = name;
this.x = x;
this.y = y;
}
Node.prototype.setX = function(x) {
this.x = x;
};
Node.prototype.setY = function(y) {
this.y = y;
};
function Nodelist() {
this.list = [];
}
Nodelist.prototype.addNode = function(node) {
this.list.push(node);
};
var a = new Node('stack', 0, 0);
var b = new Node('overflow', 0, 0);
var l = new Nodelist();
var m = new Nodelist();
l.addNode(a);
l.addNode(b);
m.addNode(a);
Do I even need these .prototype.set functions? Playing around in the console it seems I can just do a node.x = 10. Thanks.
not sure what your intention is (setters with no getters?), but you might be interested in private variables. to achieve the effect of private variables, you would start with the following:
function Guy(name) {
var _name = name;
this.getName = function(){ return _name; }
this.setName = function(n) { _name = n; }
}
var g = new Guy("Bob");
alert(g.getName()); // works
alert(g._name); // doesn't work
(In fact in this simple example, you don't even need the variable _name; getName and setName can close over the function argument name);
No, you don't need those functions, unless you need some sort of callback-based system where a function should be executed when the value changes. You can access and assign to the properties directly, as you discovered.
Javascript objects properties are accessible from anywhere ie. there are no real private variables so defining getter setter methods in this way is kind of pointless. If you want private variables or similar behaviour, read this http://javascript.crockford.com/private.html
It depends on if you're trying to enforce the encapsulation of x and y in an OOP manner. One way that javascript differs from - for example - Java is that it doesn't inherently enforce private variables. Usually, the common way to declare that some variable/method SHOULD be private is to name it with an underscore. So if you're actually trying to enforce OOP concepts here, then declare x and y like this:
function Node(name, x, y) {
this.name = name;
this._x = x;
this._y = y;
}
And then keep your setters. If you aren't trying to enforce some kind of encapsulation of x and y to your Node, then go ahead and don't provide them and just use the node.x/node.y when you need to get/set x or y.
Just keep in mind that this is simply a naming convention and when this script is running, _x is just as visible as x. It will be up to you and any programmers you work with to enforce this.