Is there a way to make a function that is being called with no parameters ? for example, I have this class
export class Student {
constructor(ssn) {
this.SSN = ssn;
}
SocialSecurityNumber() {
return this.SSN;
}
}
I want to be able to do this:
let student = new Student(123456);
console.log(student.SocialSecurityNumber);
this doesnt work now, but is there a syntax that I can use to accomplish this ?
Just to add that an alternative to calling the function with parenthesis student.socialSecurityNumber(), you could make this a getter:
class Student {
constructor(ssn) {
this.SSN = ssn;
}
get socialSecurityNumber() {
return this.SSN;
}
}
const student = new Student(123456);
console.log(student.socialSecurityNumber);
That way you could call it with the same syntax as a property.
If you are supporting Object methods, you can add object properties similar to the syntactic sugar you'd see in C#.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty
Basically,
Object.defineProperty(this,
'SocialSecurityNumber',
{
get: function() { return this.SocialSecurityNumber(); }
}
inside your constructor
Related
I have a CameraBuilder class that looks like this:
class CameraBuilder {
constructor() {
if (arguments.length) {
throw new Error('[CameraBuilder constructor ERROR] class constructor does not accept parameters.');
}
this.camera = {};
}
withFarmLabel(farmLabel) {
this.camera.farm_label = farmLabel;
return this;
}
// more methods here
build() {
const missingProps = [];
if (!this.camera.farm_label) {
missingProps.push('\nMissing farm_label property. Use the withFarmLabel method in order to assign it.');
}
// more validations like the one above here
if (missingProps.length) {
const errorMsg = missingProps.join('');
throw new Error(`[CameraBuilder build ERROR] ${errorMsg}`);
}
return this.camera;
}
}
Since most of my validations are on the build() method and there are some business logic on some of these methods associated with how the user is building an instance of CameraBuilder, I wouldn't want anyone assigning cameraBuilderObj.camera directly. Is there any way I can enforce the use of the Class methods in order to assign properties to the Camera object?
You could make the camera property private by putting # in front of it, ensuring that only CameraBuilder's internals can reference it:
class CameraBuilder {
#camera = {};
constructor() {
if (arguments.length) {
throw new Error('[CameraBuilder constructor ERROR] class constructor does not accept parameters.');
}
}
withFarmLabel(farmLabel) {
this.#camera.farm_label = farmLabel;
return this;
}
// more methods here
build() {
const missingProps = [];
if (!this.#camera.farm_label) {
missingProps.push('\nMissing farm_label property. Use the withFarmLabel method in order to assign it.');
}
// more validations like the one above here
if (missingProps.length) {
const errorMsg = missingProps.join('');
throw new Error(`[CameraBuilder build ERROR] ${errorMsg}`);
}
return this.#camera;
}
}
const c = new CameraBuilder();
c.withFarmLabel('label');
console.log(c.camera);
console.log(c.build().farm_label);
CertainPerformance's answer probably makes more sense--don't expose it in the first place--but if for some reason you didn't want to go that route (or if you're in an environment where private fields aren't supported) you could define setters on it, so that direct assignments go through your function.
class Foo {
constructor () {
this._bar = 'baz';
}
set bar (value) {
this._bar = value;
console.log('do whatever you want to do here.');
}
}
const f = new Foo();
f.bar = 'hey'; // direct assignment invokes the setter
The following is an example of an ES6 Class.
class Car {
constructor(brand) {
this.brand = brand;
// this.setBrand(brand); // how is it possible to do this?
}
setBrand(brand) {
this.brand = brand;
}
getBrand() {
return this.brand;
}
getAd() {
return `${this.brand} is the best brand out there!!`;
}
}
However, since the constructor is just a repeat of the method setBrand, I was wondering how it would be possible to remove the redundancy and perhaps call setBrand from within the constructor.
Any pointers?
You can do as you suspect. In the constructor this is a reference to the new object so you can call class methods in it. The code below runs properly.
class Car {
constructor(brand) {
this.setBrand(brand); // this works fine
}
setBrand(brand) {
this.brand = brand;
}
getBrand() {
return this.brand;
}
getAd() {
return `${this.brand} is the best brand out there!!`;
}
}
let car = new Car("DeLorean")
console.log(car.getBrand())
console.log(car.getAd())
You can call the method by doing:
class Car {
constructor(brand) {
this.setBrand(brand); <--------
}
setBrand(brand) {
this.brand = brand;
}
}
in this case it's ok because you are only assigning a value to a property, but keep in mind it's a bad practice to make the constructor do anything other than create the object.
The code below works, but my gut tells me this isn't the most succinct way to do this. I'd like to use this.function2() instead of videoControler.function2(), but that doesn't work. Is this the best way to write this?
const myController = {
function1() {
return res.json({
blah: myController.function2()
})
},
function2() {
return "blah"
}
}
Definitely check out #Teemu's link in the comment but another way to handle this is by using classes.
For instance:
class myController {
constructor(type) {
this.controllerType = type;
}
function1(x) {
return res.json({
blah: this.function2()
});
}
function2(x) {
return "blah";
}
}
And this would follow the properties of OOP where you can instantiate a new myController("video") object and invoke functions belonging to the class, outside the class as well.
In your example, replacing myController to this will point to currect scope, so it will not work. You should bind function1 to myController, and create reference to this outside the return state object, like const self = this;
I want to write code like
class Place {
next: Place;
get to() : Place {
return this;
}
}
let places : Place[]= [];
..
places[0].to.next = new Place();
There are many similar classes, so I want define 'to' property to Object.prototype.
Object.defineProperty(Object.prototye,"to",{
get: function() {
return this;
}
});
But compilation has failed because of Property 'next' does not exist on type 'Object'
Can I return subtype in Typescript with Object.prototype function or property?
Typescript can't model exactly the beahavior you want.
The closest I can think of is to use a method not a property. For methods we can define a this parameter and infer it's type and use it as the return type:
class Place extends Object{
next: Place;
}
let places: Place[] = [];
interface Object{
to<T>(this: T):T;
}
Object.prototype.to = function () {
return this;
};
places[0].to().next = new Place();
The simplest solution would be to actually use a base class for all such objects with the property typed as polymorphic this:
class Base {
get to(): this { return this; }
}
class Place extends Base{
next: Place;
}
let places: Place[] = [];
places[0].to.next = new Place();
Note: Polluting the global Object does not seem like a great idea but ultimately that is your call.
I found some solution.
TS have a return type "this";
class Entity {
self() : this {
return this;
}
}
class Place extends Entity {
where(toGo:string) {
....
}
}
and I can use place like
new Place().self().where("Canada");
method self is decleared at super class but it can return sub class type.
So, I can use place instance without type casting.
I have this typescript code:
module MyPage {
export class MyVm {
ToDo : string;
Load() {
//can access todo here by using this:
this.ToDo = "test";
$.get("GetUrl", function (servertodos) {
//but how do I get to Todo here??
this.ToDo(servertodos); //WRONG ToDo..
});
}
}
}
The question is, how do I access the todo member field in the $.get callback?
TypeScript also supports arrow function that preserve lexical scoping. Arrow functions result in similar code to Jakub's example but are neater as you don't need to create the variable and adjust usage yourself:
Here is the example using an arrow function:
$.get("GetUrl", (todos) => {
this.ToDo(todos);
});
The same way you do it in javascript
export class MyVm {
ToDo : string;
Load() {
//can access todo here by using this:
this.ToDo = "test";
var me = this;
$.get("GetUrl", function (todos) {
//but how do I get to Todo here??
me.ToDo(todos); //WRONG ToDo..
});
}
}
Fenton is right.
But you can also do this:
mycallback(todos, self) { self.todo(todos)); }
$.get('url', mycallback(todos, this));