Can we delete ES6 class? - javascript

Can we really delete a class create by es6 "class"?
class myClass{}
delete myClass;
console.log(myClass); //output: class myClass{}
var myClass=0; //Uncaught SyntaxError: Identifier 'myClass' has already been declared

Delete will only delete object properties or a variable that is global.

https://stackoverflow.com/a/44694753/461412
this answer is useful. yet not perfect.
i guess you could never delete it after it's declared as an identifier, but you could wrap it into a deletable variable in the first place.
still i'm looking for a better solution. our team is trying to build a detachable modules system. deadly, any declared class is not detachable. we don't like the idea of transpiling every module we load.

This is what I used:
window.MyClass = class extends SuperClass {} // in an external file
// load the file into a script tag, append it to the body, and execute the following after it loads:
alert(MyClass); // Outputs the class
delete window.MyClass;
alert(MyClass); // Outputs Uncaught ReferenceError: MyClass is not defined
It works fairly well. Using this approach I can import .js files into my document using script tags, access the code from the window object, and then remove the script tag and remove the reference to the class. I haven't done much testing on it, but it could be used to load custom logic for a single level in a game and then get rid of it, or something more useful perhaps. Honestly, it feels really hacky to do this.

This is the closest I could get to "remove" a Constructor
class MyClass {
constructor(a, b) {
this.a = a;
}
}
MyClass = null;
console.log( MyClass ); // -> null
var testObj = new MyClass_("val"); // -> TypeError
This does NOT delete the Constructor, it just changes the value of "MyClass" to null!
But for debugging purposes that'll do

I've made a worker for resolving the deletion of import classes.
worker.js
onmessage = function(e) {
let v = JSON.parse(e.data)
...
import(`module.js?p=${v.query}`)
.then(module => {
let obj = new module.default(v.params)
...
postMessage(obj.result)
})
main.js
async function doInBackground(x,y, output) {
let r = await new Promise((resolve, reject) => {
let w = new Worker('worker.js')
w.postMessage(JSON.stringify({
"x" : x,
"y" : y
}))
w.onmessage = function(e) {
resolve(e.data)
delete w
}
w.onerror = reject
})
output.result = r
}

Related

how to use a global variable when it takes a value in another file

I have a file called app.js:
let id = 0;
const Func = require('./func.js');
Func.myFunc();
console.log(id);
module.exports = {
id
};
Also I have another file called func.js:
const App = require('./app.js');
var myFunc = () => {
App.id = 100;
}
module.exports = {
myFunc
};
But console.log(id) returns: 0
What you are doing is termed circular dependencies. It is generally frowned upon and there is no allowed instance where this may be required. You're better off creating a third file that will use both of them...
Read this to have a better understanding:
https://nodejs.org/api/modules.html#modules_cycles
How to deal with cyclic dependencies in Node.js
Add another log like:
// app.js ...
console.log(module.exports);
module.exports = { id };
console.log(id);
to see that your code does work somehow, in the way that module.exports has an id property set, but you override that afterwards. Also the property of the export object has nothing todo with the id variable (well, the later gets copied into the first) so console.log will never log 100.
There are two problems with your piece of code:
the circular dependency
module.exports.id is not the same object as the variable id in app.js
In order to solve the first problem, you should create a third file where the variable will be declared and other modules will use that.
Now, to illustrate the second problem, look at the following.
// testModule.js
let variable = 0;
function get_variable() {
return variable;
}
module.exports = {variable, get_variable};
// app.js
const testModule = require('./testModule.js');
testModule.variable = 1234;
console.log(testModule.variable); // will print '1234'
console.log(testModule.get_variable()); // will print '0'
This little misunderstanding of modules, could lead to subtle nasty bugs. I consider that the best practice to solve this would be not to export the 'variable' property directly, but having getter/setter functions in the module, almost like transforming it into a class-like thing.
// testModule.js
let variable = 0;
function get_variable() {
return variable;
}
function set_variable(value) {
variable = value;
}
module.exports = {get_variable, set_variable};

Cannot call subclass function in Gnome Shell Extension ES6

I am trying to write a GNOME shell extension. I have a class which extends a GNOME shell type. Whenever I call class method on this subclass, it throws an error. If I do not extend the class, then the method is invoked without a problem.
Example:
This works
var Dummy = class Dummy {
constructor() {}
foo() {
log("foo!")
}
};
let d = new Dummy();
d.foo();
--> RESULT: log shows "foo!"
However, this does not work
const St = imports.gi.St;
var Dummy = class Dummy extends St.Bin {
constructor() {
super();
}
foo() {
log("foo!")
}
};
let d = new Dummy();
d.foo();
--> RESULT: TypeError: d.foo is not a function
I'm not very proficient in Javascript, and I'm having trouble Googling my way out of this situation.
Any help is appreciated. Thanks!
Unfortunately there is a bit of mix of Class styles, for couple reasons, but namely because GJS existed before ES6 classes. You should avoid usage of the Lang module if at all possible.
Sometimes it won't be clear if the object you're subclassing is a native JS class or a GObject. Any object coming from imports.gi (GObject Introspection) will be a GObject, while objects coming from say imports.ui.popupMenu (an import in GNOME Shell) could be either and you may have to check the source.
If you are subclassing a GObject, this is the proper way to subclass:
var Bin = GObject.registerClass({
// This is optional, but useful to avoid namespace collisions. By
// convention you prefix your GType's like StBin or GtkBin.
GTypeName: 'PohoBin',
// Custom GProperties
Properties: {
'example-prop': GObject.ParamSpec.string(
'example-prop', // property name
'ExampleProperty', // nickname
'An example read write property', // description
(GObject.ParamFlags.READWRITE | // READABLE/READWRITE/CONSTRUCT/etc
GObject.ParamFlags.CONSTRUCT),
null // implement defaults manually
)
}
}, class Bin extends St.Bin {
// Currently GObjects use `constructor()` for bootstrapping; you
// should not call this function in GObject subclasses.
//
// Instead, you should chain-up to the parent class's _init() function,
// which takes a dictionary of properties
_init(params = {}) {
// Chaining up. If you need to, you can use this opportunity to
// pull properties from the #params dictionary
super._init(params);
}
get example_prop() {
if (this._example_prop === undefined)
this._example_prop = null;
return this._example_prop;
}
set example_prop(value) {
if (this.example_prop !== value) {
this._example_prop = value;
this.notify('example-prop');
}
}
foo() {
log(this.example_prop);
}
});
let obj = new Bin({
visible: true, // Clutter.Actor property
x_align: St.Align.MIDDLE, // St.Bin property
example_prop: 'example' // custom property
});
obj.foo();
// expected output: 'example'
There is more information about mapping GObject to JavaScript here:
https://gitlab.gnome.org/GNOME/gjs/wikis/Mapping
There are also a number of more complete examples here:
https://gitlab.gnome.org/GNOME/gjs/tree/master/examples

Why can’t I access a property on “this” in a class via its prototype?

I wrote this class and have set up an array property for it. Then, I want to add an item to this array.
However, when I try to do it, I get the error “Uncaught TypeError: Cannot read property push of undefined”.
Isn’t this possible?
class test {
constructor() {
this.myArray = [];
}
myMethod() {
this.myArray.push("ok");
}
};
console.log(test.prototype.myMethod());
That’s not how classes are used. You need to instantiate test first, by using new test(). The constructor was never called in your case, so this.myArray was never defined.
This is the only way this can work:
let testInstance = new test();
testInstance.myMethod();
This way, the constructor is called and there will be no error.
Of course, next you’ll need some way of retrieving your array, in order to see the effect.
try to create the instance first. See the code I've commented it in details
test.prototype = {
constructor: test,
myMethod: function() {
this.myArray.push("ok");
}
};
var test = function(){
this.myArray = [];
}
test.prototype = { // add our custom constructor and custom methods
constructor: test,
myMethod: function() {
this.myArray.push("ok");
}
};
var myVar = new test(); // create new instance of test
myVar.myMethod(); // run custom method to push val
console.log( myVar.myArray );
You need to initiate your class test first.
var t = new test();
For your information:
console.log(test.prototype.myMethod());
will give you "undefined". Try e.g. :
var t = new test();
t.myMethod();
console.log(t.myArray);
to get output similar to this:
Array [ "ok" ]

Richembed not working [duplicate]

I am defining an object like this:
function Project(Attributes, ProjectWidth, ProjectHeight) {
this.ProjectHeight = ProjectHeight;
this.ProjectWidth = ProjectWidth;
this.ProjectScale = this.GetProjectScale();
this.Attributes = Attributes;
this.currentLayout = '';
this.CreateLayoutArray = function()
{....}
}
I then try to create an instance like this:
var newProj = new Project(a,b,c);
but this exception is thrown:
Project is not a constructor
What could be wrong? I googled around a lot, but I still can't figure out what I am doing wrong.
The code as posted in the question cannot generate that error, because Project is not a user-defined function / valid constructor.
function x(a,b,c){}
new x(1,2,3); // produces no errors
You've probably done something like this:
function Project(a,b,c) {}
Project = {}; // or possibly Project = new Project
new Project(1,2,3); // -> TypeError: Project is not a constructor
Variable declarations using var are hoisted and thus always evaluated before the rest of the code. So, this can also be causing issues:
function Project(){}
function localTest() {
new Project(1,2,3); // `Project` points to the local variable,
// not the global constructor!
//...some noise, causing you to forget that the `Project` constructor was used
var Project = 1; // Evaluated first
}
An additional cause of this can be ES2015 arrow functions. They cannot be used as constructors.
const f = () => {};
new f(); // This throws "f is not a constructor"
For me it was the differences between import and require on ES6.
E.g.
processor.js
class Processor {
}
export default Processor
index.js
const Processor = require('./processor');
const processor = new Processor() //fails with the error
import Processor from './processor'
const processor = new Processor() // succeed
I've googled around also and found this solution:
You have a variable Project somewhere that is not a function. Then the new operator will complain about it. Try console.log(Project) at the place where you would have used it as a construcotr, and you will find it.
For my project, the problem turned out to be a circular reference created by the require() calls:
y.js:
var x = require("./x.js");
var y = function() { console.log("result is " + x(); }
module.exports = y;
x.js:
var y = require("./y.js");
var my_y = new y(); // <- TypeError: y is not a constructor
var x = function() { console.log("result is " + my_y; }
module.exports = x;
The reason is that when it is attempting to initialize y, it creates a temporary "y" object (not class, object!) in the dependency system that is somehow not yet a constructor. Then, when x.js is finished being defined, it can continue making y a constructor. Only, x.js has an error in it where it tries to use the non-constructor y.
I have a class in one file that I'm importing into a test file:
//Vec.js
class Vec {
}
module.exports.Vec = Vec;
Changing
//Vec.test.js
const Vec = require('./Vec');
const myVec = new Vec(); //TypeError: Vec is not a constructor
to
//Vec.test.js
const {Vec} = require('./Vec');
const myVec = new Vec(); //Succeeds!
resolved this error for me.
In my case I was using the prototype name as the object name. For e.g.
function proto1()
{}
var proto1 = new proto1();
It was a silly mistake but might be of help to someone like me ;)
Sometimes it is just how you export and import it. For this error message it could be, that the default keyword is missing.
export default SampleClass {}
Where you instantiate it:
import SampleClass from 'path/to/class';
let sampleClass = new SampleClass();
Option 2, with curly braces:
export SampleClass {}
import { SampleClass } from 'path/to/class';
let sampleClass = new SampleClass();
I just want to add that if the constructor is called from a different file, then something as simple as forgetting to export the constructor with
module.exports = NAME_OF_CONSTRUCTOR
will also cause the "Not a constructor" exception.
To add to #wprl's answer, the ES6 object method shorthand, like the arrow functions, cannot be used as a constructor either. 😅
const o = {
a: () => {},
b() {},
c: function () {}
};
const { a, b, c } = o;
new a(); // throws "a is not a constructor"
new b(); // throws "b is not a constructor"
new c(); // works
Car.js
class Car {
getName() {return 'car'};
}
export default Car;
TestFile.js
const object = require('./Car.js');
const instance = new object();
error: TypeError: instance is not a constructor
printing content of object
object = {default: Car}
append default to the require function and it will work as contructor
const object = require('object-fit-images').default;
const instance = new object();
instance.getName();
In my case this happened due to a circular reference between two classes. I imported class B in the class A file and imported class A in the class B file, so the program never reached to the point of actually define A as a class.
I just had a similar error when trying to use the BS5ModalJS in conjunction with webpack, meaning I was trying to import the js file.
Because the single .js file provided was designed to be used via the script tags, it took a while for me to realise that to avoid the "BSModal is not a constructor" error, I had to go into their code and add:
export {BSModal}
I was then able to use
import { BSModal } from './../thirdparty/BS5ModalJS/BS5Modal.js';
and do
let myModal enter code here= new BSModal(...)
without getting that error.
So if you're using webpack, perhaps make sure the classes and functions are exported (and therefore available) to the callers.
In my case I'd forgotten the open and close parantheses at the end of the definition of the function wrapping all of my code in the exported module. I.e. I had:
(function () {
'use strict';
module.exports.MyClass = class{
...
);
Instead of:
(function () {
'use strict';
module.exports.MyClass = class{
...
)();
The compiler doesn't complain, but the require statement in the importing module doesn't set the variable it's being assigned to, so it's undefined at the point you try to construct it and it will give the TypeError: MyClass is not a constructor error.
I had a similar error and my problem was that the name and case of the variable name and constructor name were identical, which doesn't work since javascript interprets the intended constructor as the newly created variable.
In other words:
function project(name){
this.name = name;
}
//elsewhere...
//this is no good! name/case are identical so javascript barfs.
let project = new project('My Project');
Simply changing case or variable name fixes the problem, though:
//with a capital 'P'
function Project(name){
this.name = name;
}
//elsewhere...
//works! class name/case is dissimilar to variable name
let project = new Project('My Project');
It is happening because you must have used another variable named "project" in your code. Something like
var project = {}
For you to make the code work, change as follows:
var project = {} into var project1 = {}
To add the solution I found to this problem when I had it, I was including a class from another file and the file I tried to instantiate it in gave the "not a constructor" error. Ultimately the issue was a couple unused requires in the other file before the class was defined. I'm not sure why they broke it, but removing them fixed it. Always be sure to check if something might be hiding in between the steps you're thinking about.
In browse (assuming your app is running), inspect, source, and make sure the javascript file for the constructor is loaded.
For me this happened because of a small typo.
I had a class export like ->
module.export = class TestClass {
constructor() {}
}
And I was trying to use this class as ->
const testClass = new TestClass();
The problem and typo was at module.export, which should be module.exports so
module.exports = class TestClass { // module.exports here instead of export
constructor() {}
}

Javascript inheritance misbehaviour

I have some js code here link deleted
If you open your js console and you'll run this code snipet
var r = new TempPopupForm("xxx");
r.create();
an error will appear
TypeError: this.init is not a function
this error is saying there is no init method implemented on this object.
But that's not true.As you can see in the code below the init method is declared.
TempPopupForm.prototype = new PopupForm();
TempPopupForm.prototype.constructor = TempPopupForm;
TempPopupForm.superclass = PopupForm.prototype;
function TempPopupForm(name) {
this.init(name);
}
TempPopupForm.prototype.init = function(name) {
TempPopupForm.superclass.init.call(this, name);
};
I guess something is wrong with the inheritance definition,but I can not figure out what it is.
BTW There are some third party dependencies.
EDIT
I was following this article and where the funcs are ordered like I have. The order actually works on the other classes, but not on this one.
http://www.kevlindev.com/tutorials/javascript/inheritance/inheritance10.htm
You need to re-order your functions and instantiation. Since your constructor is using one of its own prototyped method to init, they both need to be above the block where you instantiate the object. JavaScript hoists top-level functions.
Try this -
function TempPopupForm(name) {
this.init(name);
}
TempPopupForm.prototype = new PopupForm();
TempPopupForm.prototype.constructor = TempPopupForm;
TempPopupForm.superclass = PopupForm.prototype;
TempPopupForm.prototype.init = function(name) {
TempPopupForm.superclass.init.call(this, name);
};
var r = new TempPopupForm("xxx");
r.create();

Categories

Resources