ES6 classes - Wrong constructor and setters behavior - javascript

I need to use setters insight ES6 classes to call some method automatically when some properties of a instance are changed.
I wrote this:
class Some {
constructor () {
this.xPos = 0;
this.yPos = 0;
}
set xPos (value) {
console.log(`xPos ${this.xPos}`);
}
set yPos (value) {
console.log(`yPos ${this.yPos}`);
}
}
let some = new Some();
But the console outputs:
xPos undefined
yPos undefined

You don't have getters for xPos and yPos, so why you get undefined.
This this.xPos = 0; calls setter for xPos, but when you want to write the value, it is going to find a variable or a getter for it, but you don't have any of them. In you case you need to work with value, or write a getter for it.
In the example I am working through getters and setters. In setter I set the value for properties and read throw getter. The getter returns the propertie's value.
class Some {
constructor () {
this.xPos = 0;
this.yPos = 0;
}
set xPos (value) {
this.xPosProp = value;
console.log(`xPos ${this.xPos}`);
}
set yPos (value) {
this.yPosProp = value;
console.log(`yPos ${this.yPos}`);
}
get xPos () {
return this.xPosProp;
}
get yPos () {
return this.yPosProp;
}
}
let some = new Some();

Related

Implementing Circle constructor in JavaScript, without ES6 classes

Eric Faust typed up a Circle constructor function in the following article about ES6 classes: https://hacks.mozilla.org/2015/07/es6-in-depth-classes/
I was wondering:
Why does he use defineProperty? Can't we just implement the behavior straight into the constructor. For example: Circle.draw = function draw() {..}
Why use get / set instead of just having the state in normal properties: Circle.circleCount?
Which properties should be implemented directly on new instance objects, via this in constructor, vs on Constructor.prototype (given how both make the properties available to new instances)?
Eric's code:
function Circle(radius) {
this.radius = radius;
Circle.circlesMade++;
}
Circle.draw = function draw(circle, canvas) { /* Canvas drawing code */ }
Object.defineProperty(Circle, "circlesMade", {
get: function() {
return !this._count ? 0 : this._count;
},
set: function(val) {
this._count = val;
}
});
Circle.prototype = {
area: function area() {
return Math.pow(this.radius, 2) * Math.PI;
}
};
Object.defineProperty(Circle.prototype, "radius", {
get: function() {
return this._radius;
},
set: function(radius) {
if (!Number.isInteger(radius))
throw new Error("Circle radius must be an integer.");
this._radius = radius;
}
});
let c1 = new Circle(10);
console.log(c1.area());
console.log(Circle.circlesMade);
My version:
function Circle(_radius) {
this.radius = _radius;
Circle.draw = function draw(circle, canvas) {
/* Canvas drawing code */
};
!Circle.circleCount ?
(Circle.circleCount = 1) //First construction
:
(Circle.circleCount = Circle.circleCount + 1);
this.area = function area() {
return Math.pow(this.radius, 2) * Math.PI;
};
}
let c1 = new Circle(10);
console.log(Circle.circleCount);
console.log(c1.area());
let c2 = new Circle(20);
console.log(Circle.circleCount);
console.log(c2.area());
I prefer using the constructor's prototype object for functions that will be shared with instances rather than defining a new function on each instance. This can save memory because you only have one instance of the function rather than a new copy for each instance you create.
You can also define circleCount on the prototype since all instances need the same number. You just need to be a little careful changing it to make sure you don't create a shadowed property on each instance. Then each instance can directly provide the count via the prototype chain.
Doing that complicates the function, but simplifies the rest of you code:
function Circle(_radius) {
this.radius = _radius;
// creating an instance increments the count for everyone
Circle.prototype.circleCount++ // not this.circleCount++ which will create a new property on instance
}
Circle.prototype.draw = function draw(circle, canvas) {
/* Canvas drawing code */
};
Circle.prototype.area = function() {
return Math.pow(this.radius, 2) * Math.PI;
}
Circle.prototype.circleCount = 0
let c1 = new Circle(10);
console.log(c1.circleCount);
console.log(c1.area());
let c2 = new Circle(20);
console.log(c2.circleCount);
console.log(c2.area());
Also, regarding the question about Object.defineProperty. It looks like he's using that so he can set getter and setter functions rather than just returning the property. You could do that with area with something like:
Object.defineProperty(Circle.prototype, "area", {
get: function() {
return Math.pow(this.radius, 2) * Math.PI;
}
});
Which would allow you to access area as if ti were a property on each instance:
c2.area // instead of a function c2.area()
You could set area as a property directly, but then if you change the radius you need to also change the area. I guess which is best depends on whether radius will ever change.

How to scope a variable to a class in javascript

I am trying to create a class using the class foo {} syntax, and want a private variable inside of it. Right now, I have something like this:
'use strict';
class foo {
constructor(x1,y1) {
var x = x1;
var y = y1;
}
get x() {
return x;
}
get y() {
return y;
}
}
Whenever I try to access foo.x and foo.y, I get a x is not found error. However, when I tried putting the variable declarations outside of the constructor, it stopped working. I'm also using static methods, so I can't abandon the class syntax without some work. How can I fix this? How can I declare a variable inside of the object, that is global and can't be found outside?
Those getters are declared on the prototype, where they cannot access the private (scoped) variables in the constructor. You'll need to use Object.defineProperty for creating instance-specific getters:
class Foo {
constructor(x, y) {
Object.defineProperties(this, {
x: {get() { return x; }, configurable: true},
y: {get() { return y; }, configurable: true}
});
}
}
This is no different than in ES5. Btw, given you don't assign to the variables, you might as well make them non-writable properties.
Well people are assuming you want to use getters and setters. If that's not the case, this will suffice:
'use strict';
class foo {
constructor(x1,y1) {
this.x = x1;
this.y = y1;
}
}
var f = new foo(10, 20);
console.log(f.x)
console.log(f.y)
JSFiddle: https://jsfiddle.net/gLxnqfrv/
Taken from es6-features this is the correct syntax for a class and it's getters and setters.
class Rectangle {
constructor (width, height) {
this._width = width
this._height = height
}
set width (width) { this._width = width }
get width () { return this._width }
set height (height) { this._height = height }
get height () { return this._height }
get area () { return this._width * this._height }
}
var r = new Rectangle(50, 20)
r.area === 1000
Important to note that there is no requirement to damage the prototype in ES6.

Moving all class variables to "this"

Here's part of my code:
class Light {
constructor(xpos,zpos,ypos,range,diffuser,diffuseg,digguseb,intensity,angle,exponent) {
this.xpos = xpos;
this.ypos = ypos;
this.zpos = zpos;
this.range = range;
this.diffuser = diffuser;
this.diffuseg = diffuseg;
this.diffuseb = diffuseb;
this.intensity = intensity;
this.angle = angle;
this.exponent;
[...]
Is there any way to move all given argument variables to this so I can access them later?
var lt = new Light(0,12,15,...);
alert(lt.zpos); //outputs '12'
I'm looking for a solution to put those 11 this lines to one
This does what you desire. The portion in mapArgsToThis which gets the argument names was taken from here. mapArgsToThis would be a helper function you would use when you want to be lazy.
var mapArgsToThis = function(func, args, thisPointer) {
var argsStr = func.toString().match(/function\s.*?\(([^)]*)\)/)[1];
var argNames = argsStr.split(',').map(function(arg) {
return arg.replace(/\/\*.*\*\//, '').trim();
}).filter(function(arg) {
return arg;
});
var argValues = Array.prototype.slice.call(args);
argNames.forEach(function(argName, index) {
thisPointer[argName] = argValues[index];
});
};
var MyConstructor = function(xpos,zpos,ypos,range,diffuser,diffuseg,digguseb,intensity,angle,exponent) {
mapArgsToThis(MyConstructor, arguments, this);
};
var myInstance = new MyConstructor(1,2,3,4,5,6,7,8,9,0);
console.log(myInstance);
Even though this is a solution, I don't recommend it. Typing out the argument mapping to your this properties is good for your fingers and is easier for others to read and know what's going on. It also doesn't allow for any processing of the argument values prior to assignment onto this.

ES6 Setting Properties

I've looked into it, and it seems as though ES6 doesn't have the ability to set properties of a class, and return that class?
class MyClass {
constructor() {
this.x = 0;
this.y = 0;
}
update(value) {
// logic
this.y = value;
return value;
}
}
var x = new MyClass();
console.log(x.update(1));
With the above, x will keep y as 0, even though setting y to 1. console.log will put out 1, but y is never actually updated. Calling x.y will result in 0.
I've also attempted returning the class, yet that doesn't work either.
class MyClass {
constructor() {
this.x = 0;
this.y = 0;
}
update(value) {
// logic
this.y = value;
return this;
}
}
var x = new MyClass();
x = x.update(1);
Using console.log(x) afterwards would once again result in y being 0, and not 1.
I'm aware of set and get, but then I wouldn't be able to perform any logic within update() or return anything.
Is this intended, or am I completely doing it wrong?
I would like to note that I'm using NodeJS.
I am doing something such as:
class.js ->
module.exports = /*class MyClass{}*/ (the above MyClass code)
app.js ->
let MyClass = require('class');
let x = new MyClass();
x.update(1);
console.log(x) (this returns the same value as x before calling update())
Calling x.y will result in 0
No it does. This suggests that your // logic is flawed. If there is no extra logic, the x.y property does end up as 1.
It works!
var x =new MyClass();
console.log(x.update(1)); //1
console.log(x.y); //1

Javascript Prototype General Enquries and Assign Id by Array Index

I am trying to learn how to work with javascripts prototype, I am only getting into it now. Please Excuse me if I ask ridiculously stupid questions
I just have a few pre-questions:
Is it worth learning? I mean it looks like a structured/clean
approach to me?
Do/should you use this with jQuery this?
is there any major problems or reason not to use it and why isn't it commonly used or am i just slow?
Actual Question:
I have the following code:
var BudgetSection = function BudgetSection(name ) {
this.id = "";
this.name = name;
this.monthlyTotal = 0.00;
this.yearlyTotal = 0.00;
this.subTotal = 0.00;
this.lineItems = [];
};
BudgetSection.prototype.calculateSubTotal = function() {
this.subTotal = ((12 * this.monthlyTotal) + this.yearlyTotal);
};
function BudgetLineItem(name) {
this.id = "";
this.name = name;
this.monthlyAmount = 0.00;
this.yearlyAmount = 0.00;
}
BudgetLineItem.prototype = {
totalAmount : function() {
var result = ((12 * this.monthlyAmount) + this.yearlyAmount);
return result;
}
};
var budgetSections = [];
section = new BudgetSection("test1");
section.lineItems.push(new BudgetLineItem('sub'));
section.lineItems.push(new BudgetLineItem('sub2'));
section.lineItems.push(new BudgetLineItem('sub3'));
budgetSections.push(section);
section = new BudgetSection("test2");
section.lineItems.push(new BudgetLineItem('sub'));
section.lineItems.push(new BudgetLineItem('sub2'));
section.lineItems.push(new BudgetLineItem('sub3'));
budgetSections.push(section);
section = new BudgetSection("test3");
section.lineItems.push(new BudgetLineItem('sub'));
section.lineItems.push(new BudgetLineItem('sub2'));
section.lineItems.push(new BudgetLineItem('sub3'));
budgetSections.push(section);
// first iterate through budgetSections
for ( var t = 0; t < budgetSections.length; t++) {
var sec = budgetSections[t];
console.log(sec);
// iterate through each section's lineItems
for (var q = 0; q< budgetSections[t].lineItems.length ; q++) {
var li = budgetSections[t].lineItems[q];
console.log(li);
}
}
the first BudgetSection "test1" is at index 0 in the budgetSections array. how can i assign the id to "section_".
And then also how can i set the id of BudgetLineItem like so: lineItemRow_<section_index><lineitem_index>
Also finally n the for loop what would be the best way to generate html?
I personally never use the new keyword if I can avoid it and do pure prototype-based programming with Object.create. Here's a simple example. I create a prototype-object called rectangle and then create an object called myRectangle which inherits from rectangle.
var rectangle = {
init: function( x, y, width, height ) {
this.x = x;
this.y = y;
this.width = width;
this.height = height;
},
move: function( x, y ) {
this.x += x;
this.y += y;
}
};
var myRectangle = Object.create( rectangle );
myRectangle.init( 0, 0, 2, 4 );
myRectangle.move( 3, 5 );
To explain in more depth what happens here, Object.create makes a new object with a specified prototype. When we access a property on an object (like init or move), it first checks the object itself. If it can't find it there, it moves up to the object's prototype and checks there. If it's not there, it checks the prototype's prototype, and keeps going up the prototype chain until it finds it.
When we call a function on an object (myRectangle.init()), this inside the function refers to that object, even if the function definition is actually on the prototype. This is called delegation - an object can delegate its responsibilities to its prototype.
A more class-like way to do this is:
function Rectangle( x, y, width, height ) {
this.x = x;
this.y = y;
this.width = width;
this.height = height;
}
Rectangle.prototype.move = function( x, y ) {
this.x +=x;
this.y +=y;
};
var myRectangle = new Rectangle( 0, 0, 2, 4 );
myRectangle.move( 3, 5 );
The problem is when we need to do a deeper inheritance hierarchy:
function Parent() {
/* expensive and possibly side-effect inducing initialization */
}
Parent.prototype.parentMethod = function() {};
function Child() {}
Child.prototype = new Parent();
We have to initialize a Parent object when all we really want is to set the Child prototype to an object based on Parent.prototype. Another option is:
Child.prototype = Object.create( Parent.prototype );
But now we've got this confusing, convoluted mess of prototype-based and class-based code. Personally, I like this instead:
var parent = {
parentMethod: function() {}
};
// Using underscore for stylistic reasons
var child = _.extend( Object.create( parent ), {
childMethod: function() {}
});
var instance = Object.create( child );
instance.parentMethod();
instance.childMethod();
No new keyword needed. No fake class system. "Objects inherit from objects. What could be more object-oriented than that?"
So what's the catch? Object.create is slow. If you're creating lots of objects, it's better to use new. You can still use Object.create to set up the prototype chain, but we'll have to wait a bit for browsers to optimize it enough for lots of instantiation.
Have you tried budgetSections[0].id = 'yourID';?

Categories

Resources