How to handle methods that take arguments in es6? - javascript

Well, I am kinda surprised that I had to ask a question about this but most examples provide a getter and setter but I have not seems a functions that takes parameters in es6 classes.
Given the following example from MDN web docs.
class Rectangle {
constructor(height, width) {
this.height = height;
this.width = width;
}
get area() {
return this.calcArea();
}
calcArea() {
return this.height * this.width;
}
}
const square = new Rectangle(10, 10);
console.log(square.area);
How can I add a method that takes n amount of arguments and returns something.
Example in old js
var doSomething = function(theThing) {
// process something
return theThingProcessed;
}

Like you did in the constructor except with a name?
class Rectangle {
constructor(height, width) {
this.height = height;
this.width = width;
}
get area() {
return this.calcArea();
}
calcArea() {
return this.height * this.width;
}
doSomething(theThing,theThing2,...n){
//process something
return theThingProcessed;
}
}
const square = new Rectangle(10, 10);
square.doSomething(theThing);
console.log(square.area);

Related

Javascript creating class object from string

Say I had a class defined within a string like the following:
`class Rectangle {
constructor(height, width) {
this.height = height;
this.width = width;
}
get area() {
return this.calcArea();
}
calcArea() {
return this.height * this.width;
}
}`
Is it possible to turn the string into a javascript class so I could run the following? Or similar..
const square = new Rectangle(10, 10);
console.log(square.area);
Looks like a duplicate of this : Using eval method to get class from string in Firefox
Don't forget to put class between parentheses.
var class_str = `(class Rectangle {
constructor(height, width) {
this.height = height;
this.width = width;
}
get area() {
return this.calcArea();
}
calcArea() {
return this.height * this.width;
}
})`;
var a = eval(class_str);
console.log(new a(10, 10));
A working demo here: http://jsbin.com/netipuluki/edit?js,console
You can turn a string into a class if you pass it to eval, like this:
eval("function MyClass(params) {/*Some code*/}");
var foo = new MyClass({a: 1, b: 2});
EDIT:
Based on comments I found out that the syntax shown in the question is ok, but it seems to be incompatible with eval as it is. However, doing some experiments I found the following trick:
eval("window['Rectangle'] = class Rectangle {constructor(height, width) {this.height = height;this.width = width;}get area() {return this.calcArea();}calcArea() {return this.height * this.width;}}");
var r = new Rectangle(50, 40);

Why is the class return empty prototype object first time in javascript?

I have a code in below, as you see when console.log the prototype of the class first time, it return empty, but the object new from this class actually can response those method, then I add function in prototype and bring new object successful, how can explain it?
codebase
class Polygon {
constructor(height, width) {
this.height = height;
this.width = width;
}
get area() {
return this.calcArea()
}
calcArea() {
return this.height * this.width;
}
}
console.log(Polygon.prototype)
polygon = new Polygon(222,122)
console.log(polygon.area)
console.log(polygon.calcArea())
Polygon.prototype.test = function(){ return "test"}
console.log(Polygon.prototype)
console.log(polygon.test())
output
Polygon {}
27084
27084
Polygon { test: [Function] }
test
how can explain it?
Methods/properties created through the class syntax are non-enumerable and it seems that the environment you log the value in doesn't show non-enumerable properties. console.log is not standardized, so different outputs in different environments have to be expected.
Creating a property through assignment always creates an enumerable property.
class Polygon {
constructor(height, width) {
this.height = height;
this.width = width;
}
get area() {
return this.calcArea()
}
calcArea() {
return this.height * this.width;
}
}
Polygon.prototype.test = function(){ return "test"}
// Note the different values for `enumerable`
console.log(Object.getOwnPropertyDescriptor(Polygon.prototype, 'calcArea'));
console.log(Object.getOwnPropertyDescriptor(Polygon.prototype, 'test'));

Updating properties of JS "class" based on other properties?

I'm relatively new to Javascript and I am trying to create a very simple physics engine for a game type project I am working on. In order to do this, I created what I understand to be the JS equivalent of a class that I can create new copies of for each object I want. The problem is that I want to be able to update a value such as the x position and have this also update things such as the x Middle position (x center of object on screen). I know this is possible by using an object literal and the getter, however I want to be able to create new objects at realtime based on what's on the screen and I couldn't figure out how to use get to make this work. Here's the general idea of what I am trying to do:
var object = function (xPos, yPos, width, height) {
this.xPos = xPos;
this.yPos = yPos;
function getXMid (xP) { return xP + width/2; }
this.xMid = getXMid (this.xPos);
function getYMid (yP) { return yP + height/2; }
this.yMid = getYMid (this.yPos);
}
var ball = new object (10, 20, 50, 50);
ball.xPos = 50;
console.log (ball.xMid); // want this to output 75 instead of 45
You're changing one property, and expecting other properties to update, unfortunately it doesn't work that way when the properties hold primitive values.
You could use setters and getters and a function to update the other properties when you set a value
var object = function(xPos, yPos, width, height) {
this._xPos = xPos;
this._yPos = yPos;
this.recalc = function() {
this.xMid = getXMid(this.xPos);
this.yMid = getYMid(this.yPos);
}
Object.defineProperty(this, 'xPos', {
get: function() {
return this._xPos;
},
set: function(v) {
this._xPos = v;
this.recalc();
}
});
Object.defineProperty(this, 'yPos', {
get: function() {
return this._yPos;
},
set: function(v) {
this._yPos = v;
this.recalc();
}
});
function getXMid(xP) { return xP + width / 2; }
function getYMid(yP) { return yP + height / 2; }
this.recalc();
}
var ball = new object(10, 20, 50, 50);
ball.xPos = 50;
console.log (ball.xMid); // want this to output 75 instead of 45

What is the "get" keyword before a function in a class?

What does get mean in this ES6 class? How do I reference this function? How should I use it?
class Polygon {
constructor(height, width) {
this.height = height;
this.width = width;
}
get area() {
return this.calcArea()
}
calcArea() {
return this.height * this.width;
}
}
It means the function is a getter for a property.
To use it, just use it's name as you would any other property:
'use strict'
class Polygon {
constructor(height, width) {
this.height = height;
this.width = width;
}
get area() {
return this.calcArea()
}
calcArea() {
return this.height * this.width;
}
}
var p = new Polygon(10, 20);
alert(p.area);
Summary:
The get keyword will bind an object property to a function. When this property is looked up now the getter function is called. The return value of the getter function then determines which property is returned.
Example:
const person = {
firstName: 'Willem',
lastName: 'Veen',
get fullName() {
return `${this.firstName} ${this.lastName}`;
}
}
console.log(person.fullName);
// When the fullname property gets looked up
// the getter function gets executed and its
// returned value will be the value of fullname
It is getter, same as Objects and Classes in OO JavaScript. From the MDN Docs for get:
The get syntax binds an object property to a function that will be called when that property is looked up.

why use this keyword in constructor function

compare code 1 and code 2, which one is correct?
function Rectangle(height, width) {
this.height = height;
this.width = width;
this.calcArea = function() { // why use this here?
return this.height * this.width;
};
}
code 2
I thought it's fine with this :
function Rectangle(height, width) {
this.height = height;
this.width = width;
calcArea = function() {
return this.height * this.width;
};
}
which one is correct?
This depends on how you view "correct":
Will either declaration fail to be parse correctly?
No, both are valid JavaScript.
Which one will calculate calcArea?
Code 1 will calculate it correctly and Code 2 does not create a member function of the Rectangle class but you can make it calculate correctly with a bit of difficulty ad redirection. See below.
Is either one good practice for creating classes?
No, neither of them. See at the bottom.
Code 1 - calcArea()
If you create a new instance of the Rectangle in code 1 then:
function Rectangle(height, width) {
this.height = height;
this.width = width;
this.calcArea = function() { // why use this here?
return this.height * this.width;
};
}
var rect = new Rectangle( 3, 4 );
console.log( rect.calcArea() );
Will correctly output 12
Code 2 - calcArea()
If you create a new instance of the Rectangle in code 2 then:
function Rectangle(height, width) {
this.height = height;
this.width = width;
calcArea = function() {
return this.height * this.width;
};
}
var rect = new Rectangle( 3, 4 );
console.log( rect.calcArea() );
Will throw an error: TypeError: rect.calcArea is not a function
calcArea is, instead, attached to the global scope so we can do:
console.log( calcArea() );
Will output NaN as calcArea in part of the global scope so has no knowledge of any instance of a Rectangle class and the global scope does not have a height or a width attribute.
If we do:
var rect = new Rectangle( 3, 4 );
width = 7; // Set in the global scope.
height = 10; // Set in the global scope.
console.log( calcArea() );
Then it will return 70 (and not 12 since, within calcArea(), this references the global scope and not the rect object).
If we change what this refers using .call() to invoke the function:
var rect = new Rectangle( 3, 4 );
width = 7; // Set in the global scope.
height = 10; // Set in the global scope.
console.log( calcArea.call( rect ) );
Then it will output 12 (since this now refers to the rect object and not to the global scope).
You probably don't want to have to do this every time you want to use calcArea().
Why Code 1 is not optimal
Code 1 will work but is not the optimal solution because each time you create a new Rectangle object it will create an calcArea attribute of that object which is a different function to any calcArea attributes of any other Rectangle object.
You can see this if you do:
function Rectangle(height, width) {
this.height = height;
this.width = width;
this.calcArea = function() { // why use this here?
return this.height * this.width;
};
}
var r1 = new Rectangle( 3, 4 ),
r2 = new Rectangle( 6, 7 );
console.log( r1.calcArea.toString() === r2.calcArea.toString() ); // Line 1
console.log( r1.calcArea === r2.calcArea ); // Line 2
Which will output true when testing the string representation of the functions are identical but false when testing whether the functions are identical.
What does this mean? If you create 10,000 instances of Rectangle then you will have 10,000 different instances of the calcArea attribute as well and each copy will require additional memory (plus time to allocate that memory and to garbage collect it at the end).
What is better practice?
function Rectangle(height, width) {
this.setHeight( height );
this.setWidth( width );
}
Rectangle.prototype.setHeight = function( height ){ this.height = height; }
Rectangle.prototype.setWidth = function( width ){ this.width = width; }
Rectangle.prototype.calcArea = function(){ return this.height * this.width; }
Then if you do:
var r1 = new Rectangle( 3, 4 ),
r2 = new Rectangle( 6, 7 );
console.log( r1.calcArea.toString() === r2.calcArea.toString() ); // Line 1
console.log( r1.calcArea === r2.calcArea ); // Line 2
It will return true for both - meaning that r1.calcArea and r2.calcArea refer to the identical function and regardless of how many instances of Rectangle there are.
If you don't use this, calcArea will not be accessible through the object of Rectangle. When you say,
this.calcArea = function () ...
you create a new variable in the current object (this) and the function will be assigned to it, so that the object will have access to it.
Try these statements, with and without this. You ll understand better.
var a = new Rectangle(1, 2);
console.log(a.calcArea());
The second version will set the global variable calcArea to do stuff specific to your object whenever an instance of your object is constructed. Use of this is required to set properties of your particular object.
When you preface your methods and properties with 'this' in your constructor they allow any new objects that get created with that constructor to use those properties and methods and have those properties and methods point to the newly created object.
If you create a new object based on your version of the Rectangle constructor that doesn't use 'this' as a preface to calcArea and look at the chrome debugger you get the following error:
Object #<Rectangle> has no method 'calcArea'
In short it simply isn't recognized.
The other aspects of not using "this" is that the method becomes 'global'.
Here is a code example to demonstrate:
function Rectangle(height, width) {
this.height = height;
this.width = width;
calcArea = function() { // Not prefaced with 'this'
return 'hello world';
};
}
var aNewObj = new Rectangle(10,10);
console.log(calcArea()) // Notice this is not aNewObj.calcArea() ...just calcArea() but its still accessible.

Categories