Perry
Perry

Reputation: 93

Reloading es6 class

I'm trying to load an external JavaScript, do some work with it, delete it and load it back again. But I'm having problems and maybe someone can help me understand why.

Here is an example of an external script to be loaded:

class ClassA {
    constructor() {
        console.log("ClassA object created");
    }
}

Here is an example of what I'm trying to do with it:

let aScript = document.createElement("script");

aScript.onload = function() {

    //test ClassA object
    let classA = new ClassA(); //OK (ClassA object created)
    classA = null //OK

    //remove/delete the script
    document.head.removeChild(aScript); //OK
    delete ClassA; //OK
    ClassA = null; //OK
    window.ClassA = null //OK

    //Try to reload the same script...
    aScript = document.createElement("script");
    aScript.src = "ClassA.js";
    document.head.appendChild(aScript);
    //...throws error: (ClassA.js:1 Uncaught SyntaxError: Identifier 
    //'ClassA' has already been declared at VM1088 ClassA.js:1)
};

aScript.src = "ClassA.js"; //loading the script for the first time.
document.head.appendChild(aScript);

Although I'm removing/deleting the script, the class object (ClassA) is still referenced in memory.

Uncaught SyntaxError: Identifier 'ClassA' has already been declared

Is it possible to remove a es6 class from memory? What am I doing wrong?

Thanks.

EDIT

The solutions for the script to be loaded:

window.ClassA = class {
    constructor() {
        console.log("ClassA object created");
    }
}

or

(function(window) {
    class ClassA {
        constructor() {
            console.log("ClassA object created");
        }
    }
}(window))

this way the same script/class can be load, delete and loaded again. See traktor53 post for further information.

Upvotes: 3

Views: 1455

Answers (1)

traktor
traktor

Reputation: 19366

No, it is not possible to remove an ES6 (ECMA2015) class declaration from memory.

In regards the script element, the JavaScript engine parses and runs the script after it has been loaded. Running the script declares ClassA in global scope. Deleting the script element doesn't remove the declaration - in the same way deleting the source file of a compiled program won't delete an object or executable file already created from it.

ES6 also introduced special arrangements for let variables, constants and classes: they are block scoped and may not be re-declared in the same block or in global scope. Trying to do so is considered a programming error:

{    // in same block scope
     let sameName = "0"; // first declaration is ok, but
     let sameName = "0"; // syntax error: redeclartion of "sameName", or
     const sameName = 0; // syntax error: redeclaration of "sameName", or
     class sameName {};  // syntax error: redeclaration of "sameName", or
}

In addition, and unlike variables declared using var, block-scoped identifiers declared in global scope using let, const or class are not made properties of the global object.

update correction: Class names are read-write and behave more like let than const declarations. You can assign a new value to a class name using the assignment operator ('=') - but attempting to declare the name a second time within global scope, or within the same block, will throw an error.

A snippet to demonstrate these aspects of class name declarations:

class ClassA {
    constructor() {
        console.log("ClassA object created");
    }
};

console.log(ClassA); // the class
console.log("ClassA is a " + typeof ClassA); // function
console.log("window ClassA property: " + 
  ( window.hasOwnProperty("ClassA") ? "yes" : "no")
);
console.log("typeof window.ClassA " + typeof window.ClassA);
 
ClassA=null;
if( ClassA === null) {
    console.log( "ClassA is assignable");
}
else {
    console.log( "ClassA is not assignable");
}

Attempting to redeclare classA at the end of the above snippet will generate an error about the redeclaration when the code is parsed - the code will not execute at all.

A solution could be to define ClassA as a global object property using a class expression:

// declare ClassA as a global property variable
window.ClassA =  class {
    constructor() {
        console.log("ClassA object created");
    }
}


console.log(ClassA); // the class
console.log(typeof ClassA); // function
delete window.ClassA; // remove global object property
console.log(typeof window.ClassA); // undefined

( A var declaration instead of the window property was not tested).

Upvotes: 3

Related Questions