In typescript, how would I successfully go about creating a class whose instances are functions? Specifically, I want all the functions in the class to return an HTMLelement.
I want to be able to have functions in that class that look like:
function givDiv() {
const div = document.createElement('div')
div.id = 'givenDiv'
// other things I might want to do to div
return div
}
Yes, this is possible. You can use the class constructor to return the element that you want. E.g.:
class MyDiv {
constructor() {
return document.createElement('div');
}
}
Usage:
const div = new MyDiv();
/* returns a <div></div> */
I dont know your scenery, but this can be very counterintuitive. You may consider using static methods. E.g.:
class CreateElement {
static create(el, props) {
return Object.assign(document.createElement(el), props);
}
static div(props = {}) {
return CreateElement.create('div', props);
}
static p(props = {}) {
return CreateElement.create('p', props);
}
}
On this class we have the generic method "create" which creates any element with the properties we assigned in "props". We use this method to create specialized methods that creates our elements for us like this:
const div = CreateElement.div();
/* creates a <div></div> */
const p = CreateElement.p({ classList: 'nice' });
/* creates a <p class="nice"></p> */
It sounds like you mean you want to create a class whose methods return HTML elements (methods are already functions):
class MyClass {
givDiv() {
const div = document.createElement('div')
div.id = 'givenDiv'
// other things I might want to do to div
return div
}
}
const myInstance = new MyClass()
// `myInstance` is an instance of `MyClass`
const div = myInstance.givDiv()
// call the `givDiv` method on the instance, returning an HTMLDivElement
Related
I have a code where a function is used to modify the existing functions and return a new function reference. I want that function to be applied to specific methods of a class.
My current code is
function modifyMethod(func) {
return function() {
console.log('working');
return func.apply(this, arguments);
};
}
function modifyClassMethods(ClassName, methodArray) {
// The code goes here
return ClassName;
}
class Temp {
hi() {
console.log("hi method");
}
}
Temp = modifyClassMethods(Temp, ["hi"]);
const temp = new Temp();
// This should print
//
// working
// hi method
temp.hi();
When I try to call the method modifyMethod with Temp.hi, func is undefined. If I create an object and then modify the method, then the new method will be applied only to the method of that particular object and not to all the objects of that particular class.
Note that this is just an example. I want to apply this modification to the methods of multiple classes. So, I can't generalize the method names also. Any code snippet for the modifyClassMethods will be helpful.
The methods defined with method syntax in the body of a class construct that aren't marked static are prototype methods and so they're on Temp.prototype, not Temp itself. So that's where you'd update them:
Temp.prototype.hi = modifyMethod(Temp.prototype.hi);
Only static methods end up on Temp itself.
You may see other functions created within the class body using the class fields proposal's syntax:
class Temp {
hi = () => {
//
};
}
Those are instance methods. They're created by the constructor, and re-created for each instance, roughly as though they'd been written like this:¹
class Temp {
constructor() {
this.hi = () => {
//
};
}
}
You can't wrap those until/unless an instance is created, as they're instance-specific.
So to wrap up, consider:
class Temp {
static staticMethod() {
// ...
}
prototypeMethod() {
// ...
}
instanceMethod = () => {
// ...
};
constructor() {
this.anotherInstanceMethod = () => {
// ...
};
this.yetAnotherInstanceMethod = function {
// ...
};
}
}
That class shows the three types of methods:
Static Methods, such as staticMethod, which you'll find on Temp (e.g., Temp.staticMethod);
Prototype Methods, such as prototypeMethod, which you'll find on Temp.prototype (e.g., Temp.prototype.prototypeMethod); and
Instance Methods, such as instanceMethod, anotherInstanceMethod, and yetAnotherInstanceMethod, which you'll find on the instances themselves, if/when any instances are created
¹ Technically, they're created as though with Object.defineProperty like this:
class Temp {
constructor() {
Object.defineProperty(this, "hi", {
value: () => {
//
},
writable: true,
configurable: true,
enumerable: true
});
}
}
...not via simple assignment. I used simple assignment in the example to keep it...simple. :-)
I have been experimenting with ES6 classes and am wondering if you can change class names dynamically? For example
class [Some dynamic name] {};
let C = class
{ // ...
}
Object.defineProperty (C, 'name', {value: 'TheName'});
// test:
let itsName = (new C()).constructor.name;
// itsName === 'TheName' -> true
There is a pretty simple way to do it:
const nameIt = (name, cls) => ({[name] : class extends cls {}})[name];
Here's the demo.
It uses an object literal to define a field with a desired name that would hold a new class. This causes the new class to automatically get the desired name. After we're done with that, we extract that new class and return it.
Note the parens around the object literal, so that curly braces don't get mistaken for a code block (...) => {...}.
Of course, putting an existing class into named fields won't change the class, so this only works if you are creating a new class. If you only need a dynamic name in one place where you define the class you are naming, you can drop an extra inheritance and just go:
const myClass = {[name]: class {
...
}}[name];
There is probably a better solution for whatever you are trying to achieve, but you can assign a class expression to an object:
let classes = {};
classes[someName] = class { ... };
This didn't really change in ES2015: if you want to create a dynamically named binding, you have to use an object or some other mapping instead.
To take it a bit further playing with dynamic class names and dynamic inheritance, when using babel you can just do something like this:
function withname(name, _parent) {
return class MyDinamicallyNamedClass extends (_parent||Object) {
static get name() { return name || _parent.name }
}
}
One way, even if not ideal, is simple with eval:
~function() {
const name = "Lorem"
eval(`
var ${name} = class ${name} {}
`)
console.log(Lorem) // class Lorem {}
}()
Note, it has to be with var. Using let, const, and plain class inside the eval won't work.
Another way with Function:
~function() {
const name = "Lorem"
const c = new Function(`
return class ${name} {}
`)()
console.log(c) // class Lorem {}
}()
Sitenote: you can pass scope variables into the Function and use them inside:
~function() {
const name = "Lorem"
const val = "foo"
const Class = new Function('val', `
return class ${name} {
constructor() {
console.log( val )
}
}
`)( val )
console.log(Class) // class Lorem {}
new Class // "foo"
}()
I have an Octree class. A key feature of an Octree is that it can create its own children.
class Octree {
...
createChildren(){
...
/* for each of the 8 new children*/
this.children.push(new Octree(/*someargs*/))
...
}
}
Now I want to inherit off of the Octree class, however, I also want the children to become the inherited class. For example class LODWorldTree extends Octree, to additionally contain some renderer data for a game. However, if I call LODWorldTree.createChildren(), then LODWorldTree.children will be an array of Octrees instead of LODWorldTrees.
What is the best way to fix this problem? While writing this it occured to I could store Octree.myClass = /*some inherited class*/, and manually set this variable for all classes that inherit from Octree. Is there a better way to do something like this? Maybe with this.prototype?
You can utilize the fact that each object has a reference to it's own constructor via the prototype:
class A {
constructor() {
this.val = 1;
this.children = [];
this.typeName = `I'm A`;
}
addSelfChild() {
this.children.push(new this.constructor(this.val + 1));
}
}
let a = new A(1);
a.addSelfChild();
a.addSelfChild();
console.dir(a);
class B extends A {
constructor(val) {
super(val);
this.typeName = `I'm B`;
}
}
let b = new B(1);
b.addSelfChild();
b.addSelfChild();
console.dir(b);
Try to use constructor attribute:
this.children.push(new this.constructor(/*someargs*/));
this.constructor is the reference for constructor for current object, so invoking it will produce new instance of the same class
How JS code should be structered when instantiating new classes inside controller class Main.
Solutions:
A: pass arguments while creating new class - new Options(args) - and let Options's constructor call its own methods.
B: create new class and call the classes' methods on the object.
Later I'd use properties from Options in another classes.
// A
class Main {
constructor(options) {
this.options = new Options(options);
{ firstProperty, secondProperty } = this.options;
this.another = new Another(firstProperty, secondProperty);
}
}
// B
class Main {
constructor(options) {
this.options = new Options();
const firstProperty = this.options.methodA(options);
const secondProperty = this.options.methodB(options);
this.another = new Another();
const anotherPropety = this.another.methodA(firstProperty);
(...)
}
}
For the purposes of decoupling I would suggest a third option.
//main.js
class Main {
constructor(options) {
this.options = options;
// all instances of class would have:
this.options.foo = 'bar'
}
method() {
return `${this.options.foo} - ${this.options.setup}`
}
}
// example.js
const options = new Options({setup: 'options'});
const example = new Main(options);
console.log(example.method());
This lets your inject your dependencies into a given class, which makes writing tests for your code far simpler. It also gives you the benefit of (as long as you maintain a common interface) swapping out Options for NewAwesomeOptions at some later point without having to find everywhere you might have hard coded it into a class.
I have a fairly simple example of a Container that stashes a value away and allows you to operate on it in isolation.
For my own interest I've translated the basic structure of this object from .prototype to class syntax. But the example uses a funky method for creating new instances of this object and I can't figure out how to replicate it in class syntax (see code below)
const Container = function(x) {
this.val = x
}
Container.prototype.map = function(f) {
return Container.of(f(this.val))
}
Container.of = function(x) { return new Container(x) } // Problem spot
This translates into (class syntax):
class Container {
constructor(x) {
this.val = x
}
map(f) {
return Container.of(f(this.val))
}
of = (x) => { // ????????
return new Container(x)
}
}
I believe that the problem is that the "of" method is simply bound to the single original instance of "Container" as a helper to make it easier to not have to write "new" every time you want to spin up an instance of this class. But I can't figure out how to replicate binding like that with the class syntax.
Is it just impossible to instantiate an own-class from one of the classe's own methods?
just declare the function as static.
class Container {
constructor(x) {
this.val = x
}
map(f) {
return Container.of(f(this.val))
}
static of(x) { // ????????
return new Container(x)
}
}