Do the javascript custom elements constructors share the same memory? - javascript

When I define a custom element like this:
customElements.define(
"my-tag",
class extends HTMLElement {
constructor() {
var data = {};
...
When I use the element multiple times, like:
<div>
<my-tag yadda="yadda"></my-tag>
<my-tag yadda="yadda2"></my-tag>
</div>
I notice that 'data' is shared among all the instances of 'my-tag'.
I also tried creating as a property, like:
customElements.define(
"my-tag",
class extends HTMLElement {
constructor() {
this.data = {};
...
But still got the same shared memory across the instances.
What am I missing?

Every Custom Element has its own scope:
<my-tag id="ONE"></my-tag>
<my-tag id="TWO"></my-tag>
<script>
customElements.define(
"my-tag",
class extends HTMLElement {
constructor() {
super() // sets AND returns this scope
.data = Math.random(); // chain on super, just because we can
console.log("constructor", this);
}
connectedCallback() {
console.log("connected" , this.id, this.data, this);
}
})
</script>

Related

i want to extend from one class but delete some property

I have some class for crud API service class
I want to extend it but spear few properties
for exam this is my class
class Parent {
public propertyToKeep: any;
public propertyToDelete: any;
constructor() { }
}
this is the child class
class Child extends Parent {
constructor() {
super();
}
}
Another file
where I don't want to see and get access to
export class comeComponent {
constructor(private child: Child) {
this.child.propertyToKeep // work
this.child.propertyToDelete // error and I can't even see it
}
}
I just came across the same use case as you and here's how I did it:
const Omit = <T, K extends keyof T>(Class: new () => T, keys: K[]): new () => Omit<T, typeof keys[number]> => Class;
Then you can use it like so :
class Child extends Omit(Parent, ['propertyToDelete']) {}
As you can see child only has one property now (it also works with methods).
The package from #nestjs/swagger has some nice helpers if you're dealing with a NestJS API. Their implementation is more complex so I guess they are keeping other stuff like their own property decorators (I am pretty new to Typescript so maybe I miss the point of all they are doing).
P.S: French guy tried to answer for first time with imperfect English so please be kind ^^
Here is one way to do it:
class Parent {
propertyToKeep = 'hi';
propertyToDelete = 'bye';
constructor() {}
}
class Child extends Parent {
constructor() {
super();
delete this.propertyToDelete;
}
}
const myObject = new Child();
console.log(myObject);
/* OUTPUT:
{
"propertyToKeep": "hi"
}
*/
You need to use Object.defineProperty function, for make a restriction in descriptor, enumerable to false and getter, setter with specific condition, here a complete example:
//A small example of how to make an invisible property in Child class.
class Parent{
constructor(){
this.propertyToKeep = "Visible";
this.propertyToDelete = "Not visible in subclass child";
}
}
Object.defineProperty(Parent.prototype, "propertyToDelete", {enumerable: false,
configurable: true,
get: function(){
if(!(this instanceof Child)){
return this._propertyToDelete;
}
},
set: function(v){
if(!(this instanceof Child)){
this._propertyToDelete = v;
}
}});
Object.freeze(Parent.prototype);
class Child extends Parent {
constructor() {
super();
}
}
//console.log(Child.prototype);
let chd = new Child();
console.log("Child: --------------------------------");
console.log(chd);
console.log(chd.propertyToDelete); //Undefined
console.log("Parent: -------------------------------");
let prt = new Parent();
console.log(prt);
console.log(prt.propertyToDelete); //"Not visible in subclass child"
/*let chdObj = Object.getOwnPropertyDescriptors(Child.prototype);
console.log(chdObj);*/
class SomeComponent{
#child;
constructor(child) {
this.#child = child;
console.log(this.#child); //{propertyToKeep: "Visible"}
console.log(this.#child.propertyToKeep /*work*/);
console.log(this.#child.propertyToDelete /*undefined*/);
}
}
//Now i will invoke SomeComponent
console.log("SomeComponent: -------------------------");
let sc = new SomeComponent(new Child());
That's not possible. If you declare an attribute in a parent class, you can't restrict his visibility in a child class.
From the model design point of view, that doesn't make sense as well. The problem you are exposing here indicates that your class hierarchy is not well designed and you must rethink and redesign it.

typescript: member variables from super class's constructor

The following code will alert undefined
class Parent {
field: string
constructor() {
alert(this.field)
}
}
class Child extends Parent {
field = 'child'
}
new Child() #=> undefined
whereas, the following alerts 'child' as expected
class Parent {
field: string
constructor() {
alert(this.field)
}
}
class Child extends Parent {
field = 'child'
constructor() {
// without referencing this.field before super(), this.field stays undefiend
this.field
super()
}
}
new Child() #=> 'child'
Is there any ways to accomplish the following conditions?
omit the whole Child's constructor declaration like the first example
grab the member variable in Child class?
What jumps to mind is:
class Parent {
constructor(public field: string) {
alert(this.field)
}
}
class Child extends Parent {
constructor() {
super('child');
}
}
new Child() #=> 'child'
This doesn't meet your conditions but I feel it is fairly compact.
Well you could defer the property access to a micortask:
class Parent {
field: string
constructor() {
Promise.resolve().then(() => {
alert(this.field)
};
}
}
But while that fullfills your conditions, it is ... still the wrong approach. Pass field as a constructor argument, as other answers show.
There's no way to accomplish your conditions, i'm pretty sure.
Grabbing the member variable in sub class happens after the base class constructor runs, and calling super() must be the first statement in a sub class constructor.
class Child extends Parent {
field = 'child';
}
// the above is equal to:
class Child extends Parent {
constructor(){ super(); this.field = 'child'; }
}
And this would cause error:
class Child extends Parent {
constructor(){
this.field = 'child'; // ERROR!
super();
}
}

Seamless way to bind reference to a class method with class instance [duplicate]

I'm new to using ES6 classes with React, previously I've been binding my methods to the current object (show in first example), but does ES6 allow me to permanently bind a class function to a class instance with arrows? (Useful when passing as a callback function.) I get errors when I try to use them as you can with CoffeeScript:
class SomeClass extends React.Component {
// Instead of this
constructor(){
this.handleInputChange = this.handleInputChange.bind(this)
}
// Can I somehow do this? Am i just getting the syntax wrong?
handleInputChange (val) => {
console.log('selectionMade: ', val);
}
So that if I were to pass SomeClass.handleInputChange to, for instance setTimeout, it would be scoped to the class instance, and not the window object.
Your syntax is slightly off, just missing an equals sign after the property name.
class SomeClass extends React.Component {
handleInputChange = (val) => {
console.log('selectionMade: ', val);
}
}
This is an experimental feature. You will need to enable experimental features in Babel to get this to compile. Here is a demo with experimental enabled.
To use experimental features in babel you can install the relevant plugin from here. For this specific feature, you need the transform-class-properties plugin:
{
"plugins": [
"transform-class-properties"
]
}
You can read more about the proposal for Class Fields and Static Properties here
No, if you want to create bound, instance-specific methods you will have to do that in the constructor. However, you can use arrow functions for that, instead of using .bind on a prototype method:
class SomeClass extends React.Component {
constructor() {
super();
this.handleInputChange = (val) => {
console.log('selectionMade: ', val, this);
};
…
}
}
There is an proposal which might allow you to omit the constructor() and directly put the assignment in the class scope with the same functionality, but I wouldn't recommend to use that as it's highly experimental.
Alternatively, you can always use .bind, which allows you to declare the method on the prototype and then bind it to the instance in the constructor. This approach has greater flexibility as it allows modifying the method from the outside of your class.
class SomeClass extends React.Component {
constructor() {
super();
this.handleInputChange = this.handleInputChange.bind(this);
…
}
handleInputChange(val) {
console.log('selectionMade: ', val, this);
}
}
You are using arrow function and also binding it in constructor. So you no need to do binding when you use arrow functions
class SomeClass extends React.Component {
handleInputChange = (val) => {
console.log('selectionMade: ', val);
}
}
OR you need to bind a function only in constructor when you use normal function like below
class SomeClass extends React.Component {
constructor(props){
super(props);
this.handleInputChange = this.handleInputChange.bind(this);
}
handleInputChange(val){
console.log('selectionMade: ', val);
}
}
Also binding a function directly in render is not recommended. It should always be in constructor
I know this question has been sufficiently answered, but I just have a small contribution to make (for those who don't want to use the experimental feature). Because of the problem of having to bind multiple function binds in the constructor and making it look messy, I came up with a utility method that once bound and called in the constructor, does all the necessary method bindings for you automatically.
Assume I have this class with the constructor:
//src/components/PetEditor.jsx
import React from 'react';
class PetEditor extends React.Component {
constructor(props){
super(props);
this.state = props.currentPet || {tags:[], photoUrls: []};
this.tagInput = null;
this.htmlNode = null;
this.removeTag = this.removeTag.bind(this);
this.handleChange = this.handleChange.bind(this);
this.modifyState = this.modifyState.bind(this);
this.handleKeyUp = this.handleKeyUp.bind(this);
this.addTag = this.addTag.bind(this);
this.removeTag = this.removeTag.bind(this);
this.savePet = this.savePet.bind(this);
this.addPhotoInput = this.addPhotoInput.bind(this);
this.handleSelect = this.handleSelect.bind(this);
}
// ... actual method declarations omitted
}
It looks messy, doesn't it?
Now I created this utility method
//src/utils/index.js
/**
* NB: to use this method, you need to bind it to the object instance calling it
*/
export function bindMethodsToSelf(objClass, otherMethodsToIgnore=[]){
const self = this;
Object.getOwnPropertyNames(objClass.prototype)
.forEach(method => {
//skip constructor, render and any overrides of lifecycle methods
if(method.startsWith('component')
|| method==='constructor'
|| method==='render') return;
//any other methods you don't want bound to self
if(otherMethodsToIgnore.indexOf(method)>-1) return;
//bind all other methods to class instance
self[method] = self[method].bind(self);
});
}
All I now need to do is import that utility, and add a call to my constructor, and I don't need to bind each new method in the constructor anymore.
New constructor now looks clean, like this:
//src/components/PetEditor.jsx
import React from 'react';
import { bindMethodsToSelf } from '../utils';
class PetEditor extends React.Component {
constructor(props){
super(props);
this.state = props.currentPet || {tags:[], photoUrls: []};
this.tagInput = null;
this.htmlNode = null;
bindMethodsToSelf.bind(this)(PetEditor);
}
// ...
}

Dynamically inherit from instance of the class in JavaScript

I am kind of struggling with inheritance in JavaScript. Let's say I have a following class:
class Parent {
constructor({ name, someOtherStuff } = {}) {
this.name = name;
this.someOtherStuff = someOtherStuff;
}
someMethod() {
// ...
}
}
and I would like to create a decorator that would allow me to do following:
#parent({
name: 'foo',
someOtherStuff: 'bar'
})
class MyClass extends Component {
myMethod() {
// ...
}
}
const instance = new MyClass();
// Those tests must pass
expect(instance.someMethod).toBeFunction();
expect(instance.name).toEqual('foo');
expect(instance.someOtherStuff).toEqual('bar');
expect(instance.myMethod).toBeFunction();
expect(instance instanceof Parent).toBe(true);
expect(instance instanceof MyClass).toBe(true);
Is there a way to create such decorator? I tried multiple solutions, but none of them really satisfies all the tests.
const parent = (...args) => (Target) => {
// Target corresponds to MyClass
const parent = new Parent(...args);
// ...
};
lodash is allowed.
Why use decorators? You can just extend parent class
class MyClass extends Parent {
constructor() {
super({name: 'foo', someOtherStuff: 'bar'});
}
}
You can use decorators to create a new class that inherits, apply some mixins, and go from there. JS classes don't have mutliple inheritance, so you can't do this directly, but you can combine the two manually or create a proxy that will do what you want.
I've been using wrapper classes for a decorator-based DI library by returning a class like so:
static wrapClass(target, {hook = noop} = {}) {
return class wrapper extends target {
static get wrappedClass() {
return target;
}
constructor(...args) {
super(...Injector.fromParams(args).getDependencies(wrapper).concat(args));
}
}
}
The decorator is really returning a new constructor with closure over the original, but that's enough for most purposes.

How to use arrow functions (public class fields) as class methods?

I'm new to using ES6 classes with React, previously I've been binding my methods to the current object (show in first example), but does ES6 allow me to permanently bind a class function to a class instance with arrows? (Useful when passing as a callback function.) I get errors when I try to use them as you can with CoffeeScript:
class SomeClass extends React.Component {
// Instead of this
constructor(){
this.handleInputChange = this.handleInputChange.bind(this)
}
// Can I somehow do this? Am i just getting the syntax wrong?
handleInputChange (val) => {
console.log('selectionMade: ', val);
}
So that if I were to pass SomeClass.handleInputChange to, for instance setTimeout, it would be scoped to the class instance, and not the window object.
Your syntax is slightly off, just missing an equals sign after the property name.
class SomeClass extends React.Component {
handleInputChange = (val) => {
console.log('selectionMade: ', val);
}
}
This is an experimental feature. You will need to enable experimental features in Babel to get this to compile. Here is a demo with experimental enabled.
To use experimental features in babel you can install the relevant plugin from here. For this specific feature, you need the transform-class-properties plugin:
{
"plugins": [
"transform-class-properties"
]
}
You can read more about the proposal for Class Fields and Static Properties here
No, if you want to create bound, instance-specific methods you will have to do that in the constructor. However, you can use arrow functions for that, instead of using .bind on a prototype method:
class SomeClass extends React.Component {
constructor() {
super();
this.handleInputChange = (val) => {
console.log('selectionMade: ', val, this);
};
…
}
}
There is an proposal which might allow you to omit the constructor() and directly put the assignment in the class scope with the same functionality, but I wouldn't recommend to use that as it's highly experimental.
Alternatively, you can always use .bind, which allows you to declare the method on the prototype and then bind it to the instance in the constructor. This approach has greater flexibility as it allows modifying the method from the outside of your class.
class SomeClass extends React.Component {
constructor() {
super();
this.handleInputChange = this.handleInputChange.bind(this);
…
}
handleInputChange(val) {
console.log('selectionMade: ', val, this);
}
}
You are using arrow function and also binding it in constructor. So you no need to do binding when you use arrow functions
class SomeClass extends React.Component {
handleInputChange = (val) => {
console.log('selectionMade: ', val);
}
}
OR you need to bind a function only in constructor when you use normal function like below
class SomeClass extends React.Component {
constructor(props){
super(props);
this.handleInputChange = this.handleInputChange.bind(this);
}
handleInputChange(val){
console.log('selectionMade: ', val);
}
}
Also binding a function directly in render is not recommended. It should always be in constructor
I know this question has been sufficiently answered, but I just have a small contribution to make (for those who don't want to use the experimental feature). Because of the problem of having to bind multiple function binds in the constructor and making it look messy, I came up with a utility method that once bound and called in the constructor, does all the necessary method bindings for you automatically.
Assume I have this class with the constructor:
//src/components/PetEditor.jsx
import React from 'react';
class PetEditor extends React.Component {
constructor(props){
super(props);
this.state = props.currentPet || {tags:[], photoUrls: []};
this.tagInput = null;
this.htmlNode = null;
this.removeTag = this.removeTag.bind(this);
this.handleChange = this.handleChange.bind(this);
this.modifyState = this.modifyState.bind(this);
this.handleKeyUp = this.handleKeyUp.bind(this);
this.addTag = this.addTag.bind(this);
this.removeTag = this.removeTag.bind(this);
this.savePet = this.savePet.bind(this);
this.addPhotoInput = this.addPhotoInput.bind(this);
this.handleSelect = this.handleSelect.bind(this);
}
// ... actual method declarations omitted
}
It looks messy, doesn't it?
Now I created this utility method
//src/utils/index.js
/**
* NB: to use this method, you need to bind it to the object instance calling it
*/
export function bindMethodsToSelf(objClass, otherMethodsToIgnore=[]){
const self = this;
Object.getOwnPropertyNames(objClass.prototype)
.forEach(method => {
//skip constructor, render and any overrides of lifecycle methods
if(method.startsWith('component')
|| method==='constructor'
|| method==='render') return;
//any other methods you don't want bound to self
if(otherMethodsToIgnore.indexOf(method)>-1) return;
//bind all other methods to class instance
self[method] = self[method].bind(self);
});
}
All I now need to do is import that utility, and add a call to my constructor, and I don't need to bind each new method in the constructor anymore.
New constructor now looks clean, like this:
//src/components/PetEditor.jsx
import React from 'react';
import { bindMethodsToSelf } from '../utils';
class PetEditor extends React.Component {
constructor(props){
super(props);
this.state = props.currentPet || {tags:[], photoUrls: []};
this.tagInput = null;
this.htmlNode = null;
bindMethodsToSelf.bind(this)(PetEditor);
}
// ...
}

Categories

Resources