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);
Related
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);
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'));
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.
I am doing some reading about class creation in Javascript. I know the concept does not exist in Javascript and that one can work with prototype.
I am trying to translate the following piece of code from Java to Javascript. Specifically, I want to have two constructors, one parameterless and one with two parameters:
public class MyClass {
int width = 10;
int height = 20;
public MyClass() { };
public MyClass(int w, int h) {
this.width = w;
this.height = h;
};
...
}
As far as I understand, I need to define my 'class' as following in Javascript:
function MyClass() {
this.width = 10;
this.height = 20;
};
But, how do I define my second constructor? I want to be able to create instances of my class two ways:
var Instance1 = new MyClass();
var Instance2 = new MyClass(33,45);
Update:
Ok, I understand my constructors cannot have the same name, because Javascript cannot recognize the different parameter types. So, if I use different names for my constructors, how am I supposed to declare them? Is the following correct?
function MyClass() {
this.width = 10;
this.height = 20;
};
MyClass.prototype.New2 = function(w,h) {
var result = new MyClass();
result.width = w,
result.height = h,
return result;
};
Javascript has no multimethods, therefore your only option is to parse arguments and act accordingly. A common idiom is to use || to check if an argument is "empty" (undefined or 0):
function MyClass(w, h) {
this.width = w || 10;
this.height = h || 20;
};
If 0 is a valid value in your context, check for undefined explicitly:
function MyClass(w, h) {
this.width = typeof w != 'undefined' ? w : 10;
this.height = typeof h != 'undefined' ? h : 20;
};
Another option is to provide arguments as an object and merge it with the "defaults" object. This is a common pattern in jquery:
function MyClass(options) {
// set up default options
var defaults = {
width: 10,
height: 20
};
var options = $.extend({}, defaults, options);
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.