Google Closure compiler: class as function argument - javascript

I can't figure out how to send class references as function arguments, so that Google Closure compiler will compile it right in advanced mode. In the below example I send a class reference to the Test1.doSomething function, which invokes a static function on the class. I've set the #param to Function, because I guess it still is a function, although I use ES6 style classes. Is there some other keyword I should use?
The below code works fine uncompiled, and also works fine if I go old school and change "class Test2" into "function Test2()". I've also tried to change the #param into function(), function(new:Test2), function(this:Test2), typeof Test2, etc, with no success.
class Test1
{
/**
* #param {!Function} typeRef
*/
doSomething(typeRef)
{
typeRef.doSomething();
}
}
class Test2
{
}
Test2.doSomething = function()
{
alert(1);
}
var t1 = new Test1();
window["t1"] = t1;
t1.doSomething(Test2);
I compile as follows:
--debug --formatting=PRETTY_PRINT --language_in ECMASCRIPT6_STRICT --language_out ECMASCRIPT6_STRICT --compilation_level ADVANCED_OPTIMIZATIONS --js Test.js --js_output_file Script.js
The result with "class Test2"
'use strict';
class $Test1$$ {
}
window.t1 = new $Test1$$;
The result with "function Test2()"
'use strict';
class $Test1$$ {
$doSomething$($typeRef$$) {
$typeRef$$.$doSomething$();
}
}
function $Test2$$() {
}
$Test2$$.$doSomething$ = function $$Test2$$$$doSomething$$() {
alert(1);
};
var $t1$$ = new $Test1$$;
window.t1 = $t1$$;
$t1$$.$doSomething$($Test2$$);
EDIT ON 29 JAN: Added a more complete example of what I'm trying to do:
class Car
{
constructor()
{
this.make = "Ford";
console.log("Car created.");
}
}
Car.create = function(registry)
{
let obj = new Car();
registry.add(obj);
return obj;
}
class Motorcycle
{
constructor()
{
this.make = "BMW";
console.log("Motorcycle created.");
}
}
Motorcycle.create = function(registry)
{
let obj = new Motorcycle();
registry.add(obj);
return obj;
}
class Registry
{
constructor()
{
this.vehicles = [];
}
add(vehicle)
{
this.vehicles.push(vehicle);
}
makeVehicle(typeRef)
{
typeRef.create(this);
}
}
function init()
{
var registry = new Registry();
registry.makeVehicle(Car);
registry.makeVehicle(Motorcycle);
registry.makeVehicle(Motorcycle);
registry.makeVehicle(Car);
registry.makeVehicle(Car);
}

To pass in a class, you can use the {typeof namespace} type:
#param {typeof Test2} TypeRef
As in your code:
class Test1
{
/**
* #param {typeof Test2} TypeRef
*/
doSomething(TypeRef)
{
(new TypeRef()).doSomething();
}
}
class Test2
{
doSomething ()
{
alert(1);
}
}
var t1 = new Test1();
window["t1"] = t1;
t1.doSomething(Test2);
Demo (don't forget to hit Compile)
When using #param (without typeof) you would pass an instance of that type*. This is far more common than passing a class itself
*: Sorry if this is not relevant but I noticed a couple of issues in the original code and wanted to show you how to fix them, even if not relevant;
To produce an instance-typed version, I had to change 3 things;
1) The Test2.doSomething assignment should be assigning to Test2.prototype;
Test2.prototype.doSomething = function()
{
alert(1);
}
Or using the ES6 Class format:
Test2
{
doSomething()
{
alert(1);
}
}
2) And to resolve a warning Test1.doSomething's #param annotation had to become Type2, as Function does not declare a Function.doSomething method.
/**
* #param {!Type2} typeRef
*/
3) The final line passes the class itself, not an instance of the class, so you should use the new operator to send in an instance of that class.
t1.doSomething(new Test2());
Cheers.

Related

How to get ES6 class constructor from class name? [duplicate]

I want create object factory using ES6 but old-style syntax doesn't work with new.
I have next code:
export class Column {}
export class Sequence {}
export class Checkbox {}
export class ColumnFactory {
constructor() {
this.specColumn = {
__default: 'Column',
__sequence: 'Sequence',
__checkbox: 'Checkbox'
};
}
create(name) {
let className = this.specColumn[name] ? this.specColumn[name] : this.specColumn['__default'];
return new window[className](name); // this line throw error
}
}
let factory = new ColumnFactory();
let column = factory.create('userName');
What do I do wrong?
Don't put class names on that object. Put the classes themselves there, so that you don't have to rely on them being global and accessible (in browsers) through window.
Btw, there's no good reason to make this factory a class, you would probably only instantiate it once (singleton). Just make it an object:
export class Column {}
export class Sequence {}
export class Checkbox {}
export const columnFactory = {
specColumn: {
__default: Column, // <--
__sequence: Sequence, // <--
__checkbox: Checkbox // <--
},
create(name, ...args) {
let cls = this.specColumn[name] || this.specColumn.__default;
return new cls(...args);
}
};
There is a small & dirty way to do that:
function createClassByName(name,...a) {
var c = eval(name);
return new c(...a);
}
You can now create a class like that:
let c = createClassByName( 'Person', x, y );
The problem is that the classes are not properties of the window object. You can have an object with properties "pointing" to your classes instead:
class Column {}
class Sequence {}
class Checkbox {}
let classes = {
Column,
Sequence,
Checkbox
}
class ColumnFactory {
constructor() {
this.specColumn = {
__default: 'Column',
__sequence: 'Sequence',
__checkbox: 'Checkbox'
};
}
create(name) {
let className = this.specColumn[name] ? this.specColumn[name] : this.specColumn['__default'];
return new classes[className](name); // this line no longer throw error
}
}
let factory = new ColumnFactory();
let column = factory.create('userName');
export {ColumnFactory, Column, Sequence, Checkbox};
For those of you that are not using ES6 and want to know how you can create classes by using a string here is what I have done to get this to work.
"use strict";
class Person {
constructor(x, y) {
this.x = x;
this.y = y;
}
}
window.classes = {};
window.classes.Person = Person;
document.body.innerText = JSON.stringify(new window.classes["Person"](1, 2));
As you can see the easiest way to do this is to add the class to an object.
Here is the fiddle:
https://jsfiddle.net/zxg7dsng/1/
Here is an example project that uses this approach:
https://github.com/pdxjohnny/dist-rts-client-web
I prefer this method:
allThemClasses.js
export class A {}
export class B {}
export class C {}
script.js
import * as Classes from './allThemClasses';
const a = new Classes['A'];
const b = new Classes['B'];
const c = new Classes['C'];
I know this is an old post, but recently I've had the same question about how to instance a class dynamically
I'm using webpack so following the documentation there is a way to load a module dynamically using the import() function
js/classes/MyClass.js
class MyClass {
test = null;
constructor(param) {
console.log(param)
this.test = param;
}
}
js/app.js
var p = "example";
var className = "MyClass";
import('./classes/'+className).then(function(mod) {
let myClass = new mod[className](p);
console.log(myClass);
}, function(failMsg) {
console.error("Fail to load class"+className);
console.error(failMsg);
});
Beware: this method is asynchronous and I can't really tell the performance cost for it,
But it works perfectly on my simple program (worth a try ^^)
Ps: To be fare I'm new to Es6 (a couple of days) I'm more a C++ / PHP / Java developer.
I hope this helps anyone that come across this question and that is it not a bad practice ^^".
Clarification
There are similar questions to this, including this SO question that was closed, that are looking for proxy classes or factory functions in JavaScript; also called dynamic classes. This answer is a modern solution in case you landed on this answer looking for any of those things.
Answer / Solution
As of 2022 I think there is a more elegant solution for use in the browser. I made a class called Classes that self-registers the property Class (uppercase C) on the window; code below examples.
Now you can have classes that you want to be able to reference dynamically register themselves globally:
// Make a class:
class Handler {
handleIt() {
// Handling it...
}
}
// Have it register itself globally:
Class.add(Handler);
// OR if you want to be a little more clear:
window.Class.add(Handler);
Then later on in your code all you need is the name of the class you would like to get its original reference:
// Get class
const handler = Class.get('Handler');
// Instantiate class for use
const muscleMan = new (handler)();
Or, even easier, just instantiate it right away:
// Directly instantiate class for use
const muscleMan = Class.new('Handler', ...args);
Code
You can see the latest code on my gist. Add this script before all other scripts and all of your classes will be able to register with it.
/**
* Adds a global constant class that ES6 classes can register themselves with.
* This is useful for referencing dynamically named classes and instances
* where you may need to instantiate different extended classes.
*
* NOTE: This script should be called as soon as possible, preferably before all
* other scripts on a page.
*
* #class Classes
*/
class Classes {
#classes = {};
constructor() {
/**
* JavaScript Class' natively return themselves, we can take advantage
* of this to prevent duplicate setup calls from overwriting the global
* reference to this class.
*
* We need to do this since we are explicitly trying to keep a global
* reference on window. If we did not do this a developer could accidentally
* assign to window.Class again overwriting any classes previously registered.
*/
if (window.Class) {
// eslint-disable-next-line no-constructor-return
return window.Class;
}
// eslint-disable-next-line no-constructor-return
return this;
}
/**
* Add a class to the global constant.
*
* #method
* #param {Class} ref The class to add.
* #return {boolean} True if ths class was successfully registered.
*/
add(ref) {
if (typeof ref !== 'function') {
return false;
}
this.#classes[ref.prototype.constructor.name] = ref;
return true;
}
/**
* Checks if a class exists by name.
*
* #method
* #param {string} name The name of the class you would like to check.
* #return {boolean} True if this class exists, false otherwise.
*/
exists(name) {
if (this.#classes[name]) {
return true;
}
return false;
}
/**
* Retrieve a class by name.
*
* #method
* #param {string} name The name of the class you would like to retrieve.
* #return {Class|undefined} The class asked for or undefined if it was not found.
*/
get(name) {
return this.#classes[name];
}
/**
* Instantiate a new instance of a class by reference or name.
*
* #method
* #param {Class|name} name A reference to the class or the classes name.
* #param {...any} args Any arguments to pass to the classes constructor.
* #returns A new instance of the class otherwise an error is thrown.
* #throws {ReferenceError} If the class is not defined.
*/
new(name, ...args) {
// In case the dev passed the actual class reference.
if (typeof name === 'function') {
// eslint-disable-next-line new-cap
return new (name)(...args);
}
if (this.exists(name)) {
return new (this.#classes[name])(...args);
}
throw new ReferenceError(`${name} is not defined`);
}
/**
* An alias for the add method.
*
* #method
* #alias Classes.add
*/
register(ref) {
return this.add(ref);
}
}
/**
* Insure that Classes is available in the global scope as Class so other classes
* that wish to take advantage of Classes can rely on it being present.
*
* NOTE: This does not violate https://www.w3schools.com/js/js_reserved.asp
*/
const Class = new Classes();
window.Class = Class;
This is an old question but we can find three main approaches that are very clever and useful:
1. The Ugly
We can use eval to instantiate our class like this:
class Column {
constructor(c) {
this.c = c
console.log(`Column with ${this.c}`);
}
}
function instantiator(name, ...params) {
const c = eval(name)
return new c(...params)
}
const name = 'Column';
const column = instantiator(name, 'box')
console.log({column})
However, eval has a big caveat, if we don't sanitize and don't add some layers of security, then we will have a big security whole that can be expose.
2. The Good
If we know the class names that we will use, then we can create a lookup table like this:
class Column {
constructor(c) {
console.log(`Column with ${c}`)
}
}
class Sequence {
constructor(a, b) {
console.log(`Sequence with ${a} and ${b}`)
}
}
class Checkbox {
constructor(c) {
console.log(`Checkbox with ${c}`)
}
}
// construct dict object that contains our mapping between strings and classes
const classMap = new Map([
['Column', Column],
['Sequence', Sequence],
['Checkbox', Checkbox],
])
function instantiator(name, ...p) {
return new(classMap.get(name))(...p)
}
// make a class from a string
let object = instantiator('Column', 'box')
object = instantiator('Sequence', 'box', 'index')
object = instantiator('Checkbox', 'box')
3. The Pattern
Finally, we can just create a Factory class that will safety handle the allowed classes and throw an error if it can load it.
class Column {
constructor(c) {
console.log(`Column with ${c}`)
}
}
class Sequence {
constructor(a, b) {
console.log(`Sequence with ${a} and ${b}`)
}
}
class Checkbox {
constructor(c) {
console.log(`Checkbox with ${c}`)
}
}
class ClassFactory {
static class(name) {
switch (name) {
case 'Column':
return Column
case 'Sequence':
return Sequence
case 'Checkbox':
return Checkbox
default:
throw new Error(`Could not instantiate ${name}`);
}
}
static create(name, ...p) {
return new(ClassFactory.class(name))(...p)
}
}
// make a class from a string
let object
object = ClassFactory.create('Column', 'box')
object = ClassFactory.create('Sequence', 'box', 'index')
object = ClassFactory.create('Checkbox', 'box')
I recommend The Good method. It is is clean and safe. Also, it should be better than using global or window object:
class definitions in ES6 are not automatically put on the global object like they would with other top level variable declarations (JavaScript trying to avoid adding more junk on top of prior design mistakes).
Therefore we will not pollute the global object because we are using a local classMap object to lookup the required class.

Simpler / better way to call shadowed prototype method?

I'm writing an object hierarchy in JavaScript, I would like to call a method on an object's parent when I've shadowed that method in the object.
E.g.:
var Base = function Base(msg) {
this.msg = msg;
}
Base.prototype.log = function(){
console.log("base log: " + this.msg);
}
var Sub = function Sub(msg) {
Base.call(this, msg);
}
Sub.prototype = Object.create(Base.prototype);
Sub.prototype.log = function() {
console.log("sub log");
this.__proto__.__proto__.log.call(this); // This works but __proto__
Object.getPrototypeOf(Object.getPrototypeOf(this)).log.call(this); // This works but is verbose
super.log(); // This doesn't work
}
var sub = new Sub('hi');
sub.log();
See the three lines at the bottom of the Sub.prototype.log function - is there a better way to do what I'm trying to do there?
The second line is the best I've been able to come up with but is very verbose!
super is not defined, obviously it wouldn't work.
You might want to try:
Sub.prototype.log = function() {
console.log("sub log");
Base.prototype.log.call(this);
}
Another way is to use the following method to inherit classes:
function extend(Child, Parent) {
var F = function() { };
F.prototype = Parent.prototype;
Child.prototype = new F();
// better to make it static (better practice in OOP world)
// e.g. Child.super = ...,
// but in your case:
Child.prototype.super = Parent.prototype;
}
So here is an example:
// ..
extend(Sub, Base);
Sub.prototype.log = function() {
console.log("sub log");
this.super.log.call(this);
}
In case of ES6:
class Base {
constructor(msg) {
this.msg = msg;
}
log(){
console.log("base log: " + this.msg);
}
}
class Sub extends Base {
constructor(msg) {
super(msg);
}
log() {
console.log("sub log");
super.log();
}
}
var sub = new Sub('hi');
sub.log();
If you want to keep the original method without using the name Base you could capture it using a closure before you change it.
(function() {
var superLog = Sub.prototype.log;
Sub.prototype.log = function() {
console.log("sub log");
superLog();
};
})();
This way there is no dependancy on how you inherit from Base.
Side note: the terminology you are looking for is 'overriding' the base method.

JavaScript: how to create object from class if I have class name as string? [duplicate]

I want create object factory using ES6 but old-style syntax doesn't work with new.
I have next code:
export class Column {}
export class Sequence {}
export class Checkbox {}
export class ColumnFactory {
constructor() {
this.specColumn = {
__default: 'Column',
__sequence: 'Sequence',
__checkbox: 'Checkbox'
};
}
create(name) {
let className = this.specColumn[name] ? this.specColumn[name] : this.specColumn['__default'];
return new window[className](name); // this line throw error
}
}
let factory = new ColumnFactory();
let column = factory.create('userName');
What do I do wrong?
Don't put class names on that object. Put the classes themselves there, so that you don't have to rely on them being global and accessible (in browsers) through window.
Btw, there's no good reason to make this factory a class, you would probably only instantiate it once (singleton). Just make it an object:
export class Column {}
export class Sequence {}
export class Checkbox {}
export const columnFactory = {
specColumn: {
__default: Column, // <--
__sequence: Sequence, // <--
__checkbox: Checkbox // <--
},
create(name, ...args) {
let cls = this.specColumn[name] || this.specColumn.__default;
return new cls(...args);
}
};
There is a small & dirty way to do that:
function createClassByName(name,...a) {
var c = eval(name);
return new c(...a);
}
You can now create a class like that:
let c = createClassByName( 'Person', x, y );
The problem is that the classes are not properties of the window object. You can have an object with properties "pointing" to your classes instead:
class Column {}
class Sequence {}
class Checkbox {}
let classes = {
Column,
Sequence,
Checkbox
}
class ColumnFactory {
constructor() {
this.specColumn = {
__default: 'Column',
__sequence: 'Sequence',
__checkbox: 'Checkbox'
};
}
create(name) {
let className = this.specColumn[name] ? this.specColumn[name] : this.specColumn['__default'];
return new classes[className](name); // this line no longer throw error
}
}
let factory = new ColumnFactory();
let column = factory.create('userName');
export {ColumnFactory, Column, Sequence, Checkbox};
For those of you that are not using ES6 and want to know how you can create classes by using a string here is what I have done to get this to work.
"use strict";
class Person {
constructor(x, y) {
this.x = x;
this.y = y;
}
}
window.classes = {};
window.classes.Person = Person;
document.body.innerText = JSON.stringify(new window.classes["Person"](1, 2));
As you can see the easiest way to do this is to add the class to an object.
Here is the fiddle:
https://jsfiddle.net/zxg7dsng/1/
Here is an example project that uses this approach:
https://github.com/pdxjohnny/dist-rts-client-web
I prefer this method:
allThemClasses.js
export class A {}
export class B {}
export class C {}
script.js
import * as Classes from './allThemClasses';
const a = new Classes['A'];
const b = new Classes['B'];
const c = new Classes['C'];
I know this is an old post, but recently I've had the same question about how to instance a class dynamically
I'm using webpack so following the documentation there is a way to load a module dynamically using the import() function
js/classes/MyClass.js
class MyClass {
test = null;
constructor(param) {
console.log(param)
this.test = param;
}
}
js/app.js
var p = "example";
var className = "MyClass";
import('./classes/'+className).then(function(mod) {
let myClass = new mod[className](p);
console.log(myClass);
}, function(failMsg) {
console.error("Fail to load class"+className);
console.error(failMsg);
});
Beware: this method is asynchronous and I can't really tell the performance cost for it,
But it works perfectly on my simple program (worth a try ^^)
Ps: To be fare I'm new to Es6 (a couple of days) I'm more a C++ / PHP / Java developer.
I hope this helps anyone that come across this question and that is it not a bad practice ^^".
Clarification
There are similar questions to this, including this SO question that was closed, that are looking for proxy classes or factory functions in JavaScript; also called dynamic classes. This answer is a modern solution in case you landed on this answer looking for any of those things.
Answer / Solution
As of 2022 I think there is a more elegant solution for use in the browser. I made a class called Classes that self-registers the property Class (uppercase C) on the window; code below examples.
Now you can have classes that you want to be able to reference dynamically register themselves globally:
// Make a class:
class Handler {
handleIt() {
// Handling it...
}
}
// Have it register itself globally:
Class.add(Handler);
// OR if you want to be a little more clear:
window.Class.add(Handler);
Then later on in your code all you need is the name of the class you would like to get its original reference:
// Get class
const handler = Class.get('Handler');
// Instantiate class for use
const muscleMan = new (handler)();
Or, even easier, just instantiate it right away:
// Directly instantiate class for use
const muscleMan = Class.new('Handler', ...args);
Code
You can see the latest code on my gist. Add this script before all other scripts and all of your classes will be able to register with it.
/**
* Adds a global constant class that ES6 classes can register themselves with.
* This is useful for referencing dynamically named classes and instances
* where you may need to instantiate different extended classes.
*
* NOTE: This script should be called as soon as possible, preferably before all
* other scripts on a page.
*
* #class Classes
*/
class Classes {
#classes = {};
constructor() {
/**
* JavaScript Class' natively return themselves, we can take advantage
* of this to prevent duplicate setup calls from overwriting the global
* reference to this class.
*
* We need to do this since we are explicitly trying to keep a global
* reference on window. If we did not do this a developer could accidentally
* assign to window.Class again overwriting any classes previously registered.
*/
if (window.Class) {
// eslint-disable-next-line no-constructor-return
return window.Class;
}
// eslint-disable-next-line no-constructor-return
return this;
}
/**
* Add a class to the global constant.
*
* #method
* #param {Class} ref The class to add.
* #return {boolean} True if ths class was successfully registered.
*/
add(ref) {
if (typeof ref !== 'function') {
return false;
}
this.#classes[ref.prototype.constructor.name] = ref;
return true;
}
/**
* Checks if a class exists by name.
*
* #method
* #param {string} name The name of the class you would like to check.
* #return {boolean} True if this class exists, false otherwise.
*/
exists(name) {
if (this.#classes[name]) {
return true;
}
return false;
}
/**
* Retrieve a class by name.
*
* #method
* #param {string} name The name of the class you would like to retrieve.
* #return {Class|undefined} The class asked for or undefined if it was not found.
*/
get(name) {
return this.#classes[name];
}
/**
* Instantiate a new instance of a class by reference or name.
*
* #method
* #param {Class|name} name A reference to the class or the classes name.
* #param {...any} args Any arguments to pass to the classes constructor.
* #returns A new instance of the class otherwise an error is thrown.
* #throws {ReferenceError} If the class is not defined.
*/
new(name, ...args) {
// In case the dev passed the actual class reference.
if (typeof name === 'function') {
// eslint-disable-next-line new-cap
return new (name)(...args);
}
if (this.exists(name)) {
return new (this.#classes[name])(...args);
}
throw new ReferenceError(`${name} is not defined`);
}
/**
* An alias for the add method.
*
* #method
* #alias Classes.add
*/
register(ref) {
return this.add(ref);
}
}
/**
* Insure that Classes is available in the global scope as Class so other classes
* that wish to take advantage of Classes can rely on it being present.
*
* NOTE: This does not violate https://www.w3schools.com/js/js_reserved.asp
*/
const Class = new Classes();
window.Class = Class;
This is an old question but we can find three main approaches that are very clever and useful:
1. The Ugly
We can use eval to instantiate our class like this:
class Column {
constructor(c) {
this.c = c
console.log(`Column with ${this.c}`);
}
}
function instantiator(name, ...params) {
const c = eval(name)
return new c(...params)
}
const name = 'Column';
const column = instantiator(name, 'box')
console.log({column})
However, eval has a big caveat, if we don't sanitize and don't add some layers of security, then we will have a big security whole that can be expose.
2. The Good
If we know the class names that we will use, then we can create a lookup table like this:
class Column {
constructor(c) {
console.log(`Column with ${c}`)
}
}
class Sequence {
constructor(a, b) {
console.log(`Sequence with ${a} and ${b}`)
}
}
class Checkbox {
constructor(c) {
console.log(`Checkbox with ${c}`)
}
}
// construct dict object that contains our mapping between strings and classes
const classMap = new Map([
['Column', Column],
['Sequence', Sequence],
['Checkbox', Checkbox],
])
function instantiator(name, ...p) {
return new(classMap.get(name))(...p)
}
// make a class from a string
let object = instantiator('Column', 'box')
object = instantiator('Sequence', 'box', 'index')
object = instantiator('Checkbox', 'box')
3. The Pattern
Finally, we can just create a Factory class that will safety handle the allowed classes and throw an error if it can load it.
class Column {
constructor(c) {
console.log(`Column with ${c}`)
}
}
class Sequence {
constructor(a, b) {
console.log(`Sequence with ${a} and ${b}`)
}
}
class Checkbox {
constructor(c) {
console.log(`Checkbox with ${c}`)
}
}
class ClassFactory {
static class(name) {
switch (name) {
case 'Column':
return Column
case 'Sequence':
return Sequence
case 'Checkbox':
return Checkbox
default:
throw new Error(`Could not instantiate ${name}`);
}
}
static create(name, ...p) {
return new(ClassFactory.class(name))(...p)
}
}
// make a class from a string
let object
object = ClassFactory.create('Column', 'box')
object = ClassFactory.create('Sequence', 'box', 'index')
object = ClassFactory.create('Checkbox', 'box')
I recommend The Good method. It is is clean and safe. Also, it should be better than using global or window object:
class definitions in ES6 are not automatically put on the global object like they would with other top level variable declarations (JavaScript trying to avoid adding more junk on top of prior design mistakes).
Therefore we will not pollute the global object because we are using a local classMap object to lookup the required class.

Adding functions to the same namespace [duplicate]

How do I create a namespace in JavaScript so that my objects and functions aren't overwritten by other same-named objects and functions? I've used the following:
if (Foo == null || typeof(Foo) != "object") { var Foo = new Object();}
Is there a more elegant or succinct way of doing this?
I use the approach found on the Enterprise jQuery site:
Here is their example showing how to declare private & public properties and functions. Everything is done as a self-executing anonymous function.
(function( skillet, $, undefined ) {
//Private Property
var isHot = true;
//Public Property
skillet.ingredient = "Bacon Strips";
//Public Method
skillet.fry = function() {
var oliveOil;
addItem( "\t\n Butter \n\t" );
addItem( oliveOil );
console.log( "Frying " + skillet.ingredient );
};
//Private Method
function addItem( item ) {
if ( item !== undefined ) {
console.log( "Adding " + $.trim(item) );
}
}
}( window.skillet = window.skillet || {}, jQuery ));
So if you want to access one of the public members you would just go skillet.fry() or skillet.ingredients.
What's really cool is that you can now extend the namespace using the exact same syntax.
//Adding new Functionality to the skillet
(function( skillet, $, undefined ) {
//Private Property
var amountOfGrease = "1 Cup";
//Public Method
skillet.toString = function() {
console.log( skillet.quantity + " " +
skillet.ingredient + " & " +
amountOfGrease + " of Grease" );
console.log( isHot ? "Hot" : "Cold" );
};
}( window.skillet = window.skillet || {}, jQuery ));
The third undefined argument
The third, undefined argument is the source of the variable of value undefined. I'm not sure if it's still relevant today, but while working with older browsers / JavaScript standards (ecmascript 5, javascript < 1.8.5 ~ firefox 4), the global-scope variable undefined is writable, so anyone could rewrite its value. The third argument (when not passed a value) creates a variable named undefined which is scoped to the namespace/function. Because no value was passed when you created the name space, it defaults to the value undefined.
I like this:
var yourNamespace = {
foo: function() {
},
bar: function() {
}
};
...
yourNamespace.foo();
Another way to do it, which I consider it to be a little bit less restrictive than the object literal form, is this:
var ns = new function() {
var internalFunction = function() {
};
this.publicFunction = function() {
};
};
The above is pretty much like the module pattern and whether you like it or not, it allows you to expose all your functions as public, while avoiding the rigid structure of an object literal.
Is there a more elegant or succinct way of doing this?
Yes. For example:
var your_namespace = your_namespace || {};
then you can have
var your_namespace = your_namespace || {};
your_namespace.Foo = {toAlert:'test'};
your_namespace.Bar = function(arg)
{
alert(arg);
};
with(your_namespace)
{
Bar(Foo.toAlert);
}
I normally build it in a closure:
var MYNS = MYNS || {};
MYNS.subns = (function() {
function privateMethod() {
// Do private stuff, or build internal.
return "Message";
}
return {
someProperty: 'prop value',
publicMethod: function() {
return privateMethod() + " stuff";
}
};
})();
My style over the years has had a subtle change since writing this, and I now find myself writing the closure like this:
var MYNS = MYNS || {};
MYNS.subns = (function() {
var internalState = "Message";
var privateMethod = function() {
// Do private stuff, or build internal.
return internalState;
};
var publicMethod = function() {
return privateMethod() + " stuff";
};
return {
someProperty: 'prop value',
publicMethod: publicMethod
};
})();
In this way I find the public API and implementation easier to understand. Think of the return statement as being a public interface to the implementation.
Because you may write different files of JavaScript and later combine or not combine them in an application, each needs to be able to recover or construct the namespace object without damaging the work of other files...
One file might intend to use the namespace namespace.namespace1:
namespace = window.namespace || {};
namespace.namespace1 = namespace.namespace1 || {};
namespace.namespace1.doSomeThing = function(){}
Another file might want to use the namespace namespace.namespace2:
namespace = window.namespace || {};
namespace.namespace2 = namespace.namespace2 || {};
namespace.namespace2.doSomeThing = function(){}
These two files can live together or apart without colliding.
Here's how Stoyan Stefanov does it in his JavaScript Patterns book which I found to be very good (it also shows how he does comments that allows for auto-generated API documentation, and how to add a method to a custom object's prototype):
/**
* My JavaScript application
*
* #module myapp
*/
/** #namespace Namespace for MYAPP classes and functions. */
var MYAPP = MYAPP || {};
/**
* A maths utility
* #namespace MYAPP
* #class math_stuff
*/
MYAPP.math_stuff = {
/**
* Sums two numbers
*
* #method sum
* #param {Number} a First number
* #param {Number} b Second number
* #return {Number} Sum of the inputs
*/
sum: function (a, b) {
return a + b;
},
/**
* Multiplies two numbers
*
* #method multi
* #param {Number} a First number
* #param {Number} b Second number
* #return {Number} The inputs multiplied
*/
multi: function (a, b) {
return a * b;
}
};
/**
* Constructs Person objects
* #class Person
* #constructor
* #namespace MYAPP
* #param {String} First name
* #param {String} Last name
*/
MYAPP.Person = function (first, last) {
/**
* First name of the Person
* #property first_name
* #type String
*/
this.first_name = first;
/**
* Last name of the Person
* #property last_name
* #type String
*/
this.last_name = last;
};
/**
* Return Person's full name
*
* #method getName
* #return {String} First name + last name
*/
MYAPP.Person.prototype.getName = function () {
return this.first_name + ' ' + this.last_name;
};
I use this approach:
var myNamespace = {}
myNamespace._construct = function()
{
var staticVariable = "This is available to all functions created here"
function MyClass()
{
// Depending on the class, we may build all the classes here
this.publicMethod = function()
{
//Do stuff
}
}
// Alternatively, we may use a prototype.
MyClass.prototype.altPublicMethod = function()
{
//Do stuff
}
function privateStuff()
{
}
function publicStuff()
{
// Code that may call other public and private functions
}
// List of things to place publically
this.publicStuff = publicStuff
this.MyClass = MyClass
}
myNamespace._construct()
// The following may or may not be in another file
myNamespace.subName = {}
myNamespace.subName._construct = function()
{
// Build namespace
}
myNamespace.subName._construct()
External code can then be:
var myClass = new myNamespace.MyClass();
var myOtherClass = new myNamepace.subName.SomeOtherClass();
myNamespace.subName.publicOtherStuff(someParameter);
This is a follow-up to user106826's link to Namespace.js. It seems the project moved to GitHub. It is now smith/namespacedotjs.
I have been using this simple JavaScript helper for my tiny project and so far it seems to be light yet versatile enough to handle namespacing and loading modules/classes. It would be great if it would allow me to import a package into a namespace of my choice, not just the global namespace... sigh, but that's besides the point.
It allows you to declare the namespace then define objects/modules in that namespace:
Namespace('my.awesome.package');
my.awesome.package.WildClass = {};
Another option is to declare the namespace and its contents at once:
Namespace('my.awesome.package', {
SuperDuperClass: {
saveTheDay: function() {
alert('You are welcome.');
}
}
});
For more usage examples, look at the example.js file in the source.
Sample:
var namespace = {};
namespace.module1 = (function(){
var self = {};
self.initialized = false;
self.init = function(){
setTimeout(self.onTimeout, 1000)
};
self.onTimeout = function(){
alert('onTimeout')
self.initialized = true;
};
self.init(); /* If it needs to auto-initialize, */
/* You can also call 'namespace.module1.init();' from outside the module. */
return self;
})()
You can optionally declare a local variable, same, like self and assign local.onTimeout if you want it to be private.
The Module pattern was originally defined as a way to provide both private and public encapsulation for classes in conventional software engineering.
When working with the Module pattern, we may find it useful to define a simple template that we use for getting started with it. Here's one that covers name-spacing, public and private variables.
In JavaScript, the Module pattern is used to further emulate the concept of classes in such a way that we're able to include both public/private methods and variables inside a single object, thus shielding particular parts from the global scope. What this results in is a reduction in the likelihood of our function names conflicting with other functions defined in additional scripts on the page.
var myNamespace = (function () {
var myPrivateVar, myPrivateMethod;
// A private counter variable
myPrivateVar = 0;
// A private function which logs any arguments
myPrivateMethod = function( foo ) {
console.log( foo );
};
return {
// A public variable
myPublicVar: "foo",
// A public function utilizing privates
myPublicFunction: function( bar ) {
// Increment our private counter
myPrivateVar++;
// Call our private method using bar
myPrivateMethod( bar );
}
};
})();
Advantages
why is the Module pattern a good choice? For starters, it's a lot cleaner for developers coming from an object-oriented background than the idea of true encapsulation, at least from a JavaScript perspective.
Secondly, it supports private data - so, in the Module pattern, public parts of our code are able to touch the private parts, however the outside world is unable to touch the class's private parts.
Disadvantages
The disadvantages of the Module pattern are that as we access both public and private members differently, when we wish to change visibility, we actually have to make changes to each place the member was used.
We also can't access private members in methods that are added to the object at a later point. That said, in many cases the Module pattern is still quite useful and when used correctly, certainly has the potential to improve the structure of our application.
The Revealing Module Pattern
Now that we're a little more familiar with the module pattern, let’s take a look at a slightly improved version - Christian Heilmann’s Revealing Module pattern.
The Revealing Module pattern came about as Heilmann was frustrated with the fact that he had to repeat the name of the main object when we wanted to call one public method from another or access public variables.He also disliked the Module pattern’s requirement for having to switch to object literal notation for the things he wished to make public.
The result of his efforts was an updated pattern where we would simply define all of our functions and variables in the private scope and return an anonymous object with pointers to the private functionality we wished to reveal as public.
An example of how to use the Revealing Module pattern can be found below
var myRevealingModule = (function () {
var privateVar = "Ben Cherry",
publicVar = "Hey there!";
function privateFunction() {
console.log( "Name:" + privateVar );
}
function publicSetName( strName ) {
privateVar = strName;
}
function publicGetName() {
privateFunction();
}
// Reveal public pointers to
// private functions and properties
return {
setName: publicSetName,
greeting: publicVar,
getName: publicGetName
};
})();
myRevealingModule.setName( "Paul Kinlan" );
Advantages
This pattern allows the syntax of our scripts to be more consistent. It also makes it more clear at the end of the module which of our functions and variables may be accessed publicly which eases readability.
Disadvantages
A disadvantage of this pattern is that if a private function refers to a public function, that public function can't be overridden if a patch is necessary. This is because the private function will continue to refer to the private implementation and the pattern doesn't apply to public members, only to functions.
Public object members which refer to private variables are also subject to the no-patch rule notes above.
If you need the private scope:
var yourNamespace = (function() {
//Private property
var publicScope = {};
//Private property
var privateProperty = "aaa";
//Public property
publicScope.publicProperty = "bbb";
//Public method
publicScope.publicMethod = function() {
this.privateMethod();
};
//Private method
function privateMethod() {
console.log(this.privateProperty);
}
//Return only the public parts
return publicScope;
}());
yourNamespace.publicMethod();
else if you won't ever use the private scope:
var yourNamespace = {};
yourNamespace.publicMethod = function() {
// Do something...
};
yourNamespace.publicMethod2 = function() {
// Do something...
};
yourNamespace.publicMethod();
You can declare a simple function to provide namespaces.
function namespace(namespace) {
var object = this, tokens = namespace.split("."), token;
while (tokens.length > 0) {
token = tokens.shift();
if (typeof object[token] === "undefined") {
object[token] = {};
}
object = object[token];
}
return object;
}
// Usage example
namespace("foo.bar").baz = "I'm a value!";
I'm 7 years late to the party, but did quite a bit of work around this 8 years ago:
http://blogger.ziesemer.com/2008/05/javascript-namespace-function.html
http://blogger.ziesemer.com/2007/10/respecting-javascript-global-namespace.html
It is important to be able to easily and efficiently create multiple nested namespaces to keep a complex web application organized and manageable, while respecting the JavaScript global namespace (preventing namespace pollution), and with not clobbering any existing objects in the namespace path while doing so.
From the above, this was my circa-2008 solution:
var namespace = function(name, separator, container){
var ns = name.split(separator || '.'),
o = container || window,
i,
len;
for(i = 0, len = ns.length; i < len; i++){
o = o[ns[i]] = o[ns[i]] || {};
}
return o;
};
This isn't creating a namespace, but provides a function for creating namespaces.
This can be condensed to a minified one-liner:
var namespace=function(c,f,b){var e=c.split(f||"."),g=b||window,d,a;for(d=0,a=e.length;d<a;d++){g=g[e[d]]=g[e[d]]||{}}return g};
Example of use:
namespace("com.example.namespace");
com.example.namespace.test = function(){
alert("In namespaced function.");
};
Or, as one statement:
namespace("com.example.namespace").test = function(){
alert("In namespaced function.");
};
Either is then executed as:
com.example.namespace.test();
If you don't need support for legacy browsers, an updated version:
const namespace = function(name, separator, container){
var o = container || window;
name.split(separator || '.').forEach(function(x){
o = o[x] = o[x] || {};
});
return o;
};
Now, I'd be leery of exposing namespace to the global namespace itself. (Too bad the base language doesn't provide this for us!) So I'd typically use this myself in a closure, such as:
(function(){
const namespace = function(name, separator, container){
var o = container || window;
name.split(separator || '.').forEach(function(x){
o = o[x] = o[x] || {};
});
return o;
};
const ns = namespace("com.ziesemer.myApp");
// Optional:
ns.namespace = ns;
// Further extend, work with ns from here...
}());
console.log("\"com\":", com);
In a larger application, this only needs to be defined once at the beginning of a page load (for client-based web apps). Additional files can then reuse the namespace function if kept (included as "optional" in the above). At worst, if this function is re-declared a few times - it's only a few lines of code, and less if minified.
I created namespace which is inspired by Erlang's modules. It is a very functional approach, but that is how I write my JavaScript code these days.
It gives a closure a global namespace and exposes a defined set functions within that closure.
(function(){
namespace("images", previous, next);
// ^^ This creates or finds a root object, images, and binds the two functions to it.
// It works even though those functions are not yet defined.
function previous(){ ... }
function next(){ ... }
function find(){ ... } // A private function
})();
After porting several of my libraries to different projects, and having to constantly be changing the top level (statically named) namespace, I've switched to using this small (open source) helper function for defining namespaces.
global_namespace.Define('startpad.base', function(ns) {
var Other = ns.Import('startpad.other');
....
});
Description of the benefits are at my blog post. You can grab the source code here.
One of the benefits I really like is isolation between modules with respect to load order. You can refer to an external module BEFORE it is loaded. And the object reference you get will be filled in when the code is available.
I use the following syntax for the namespace.
var MYNamespace = MYNamespace|| {};
MYNamespace.MyFirstClass = function (val) {
this.value = val;
this.getValue = function(){
return this.value;
};
}
var myFirstInstance = new MYNamespace.MyFirstClass(46);
alert(myFirstInstance.getValue());
jsfiddle: http://jsfiddle.net/rpaul/4dngxwb3/1/
I think you all use too much code for such a simple problem.
No need to make a repo for that.
Here's a single line function.
namespace => namespace.split(".").reduce((last, next) => (last[next] = (last[next] || {})), window);
Try it :
// --- definition ---
const namespace = name => name.split(".").reduce((last, next) => (last[next] = (last[next] || {})), window);
// --- Use ----
const c = namespace("a.b.c");
c.MyClass = class MyClass {};
// --- see ----
console.log("a : ", a);
ES6 Modules Namespace imports
// circle.js
export { name, draw, reportArea, reportPerimeter };
// main.js
import * as Circle from './modules/circle.js';
// draw a circle
let circle1 = Circle.draw(myCanvas.ctx, 75, 200, 100, 'green');
Circle.reportArea(circle1.radius, reportList);
Circle.reportPerimeter(circle1.radius, reportList);
This grabs all the exports available inside circle.js, and makes them available as members of an object Circle, effectively giving it its own namespace.
My favorite pattern has become lately this:
var namespace = (function() {
// expose to public
return {
a: internalA,
c: internalC
}
// all private
/**
* Full JSDoc
*/
function internalA() {
// ...
}
/**
* Full JSDoc
*/
function internalB() {
// ...
}
/**
* Full JSDoc
*/
function internalC() {
// ...
}
/**
* Full JSDoc
*/
function internalD() {
// ...
}
})();
Of course, return can be at the end, but if only function declarations follow it, it's much easier to see what's the namespace all about, and what API is exposed.
The pattern of using function expressions in such cases results in not being able to know what methods are exposed without going over the entire code.
I like Jaco Pretorius' solution, but I wanted to make the "this" keyword a bit more useful by pointing it to the module/namespace object.
My version of skillet:
(function ($, undefined) {
console.log(this);
}).call(window.myNamespace = window.myNamespace || {}, jQuery);
JavaScript does not yet have a native representation of namespaces, but TypeScript does.
For example, you could use the following TS code (playground)
namespace Stack {
export const hello = () => console.log('hi')
}
Stack.hello()
If you can't update your code to TS, you can at least use the pattern employed by TS when generating the JS output for namespaces, which looks like this:
var Stack;
(function (Stack) {
Stack.hello = () => console.log('hi');
})(Stack || (Stack = {}));
Stack.hello();
Further Reading:
TS - Namespaces
TS - Namespaces and Modules
If using a Makefile you can do this.
// prelude.hjs
billy = new (
function moduleWrapper () {
const exports = this;
// postlude.hjs
return exports;
})();
// someinternalfile.js
function bob () { console.log('hi'); }
exports.bob = bob;
// clientfile.js
billy.bob();
I prefer to use a Makefile anyway once I get to about 1000 lines because I can effectively comment out large swaths of code by removing a single line in the makefile. It makes it easy to fiddle with stuff. Also, with this technique the namespace only appears once in the prelude so it's easy to change and you don't have to keep repeating it inside the library code.
A shell script for live development in the browser when using a makefile:
while (true); do make; sleep 1; done
Add this as a make task 'go' and you can 'make go' to keep your build updated as you code.
Quite a follow-up of Ionuț G. Stan's answer, but showing the benefits of uncluttered code by using var ClassFirst = this.ClassFirst = function() {...}, which takes advantage of JavaScript's closure scoping for less namespace cluttering for classes in the same namespace.
var Namespace = new function() {
var ClassFirst = this.ClassFirst = function() {
this.abc = 123;
}
var ClassSecond = this.ClassSecond = function() {
console.log("Cluttered way to access another class in namespace: ", new Namespace.ClassFirst().abc);
console.log("Nicer way to access a class in same namespace: ", new ClassFirst().abc);
}
}
var Namespace2 = new function() {
var ClassFirst = this.ClassFirst = function() {
this.abc = 666;
}
var ClassSecond = this.ClassSecond = function() {
console.log("Cluttered way to access another class in namespace: ", new Namespace2.ClassFirst().abc);
console.log("Nicer way to access a class in same namespace: ", new ClassFirst().abc);
}
}
new Namespace.ClassSecond()
new Namespace2.ClassSecond()
Output:
Cluttered way to access another class in namespace: 123
Nicer way to access a class in same namespace: 123
Cluttered way to access another class in namespace: 666
Nicer way to access a class in same namespace: 666
I've written another namespacing library that works a bit more like packages / units do in other languages. It allows you to create a package of JavaScript code and the reference that package from other code:
File hello.js
Package("hello", [], function() {
function greeting() {
alert("Hello World!");
}
// Expose function greeting to other packages
Export("greeting", greeting);
});
File Example.js
Package("example", ["hello"], function(greeting) {
// Greeting is available here
greeting(); // Alerts: "Hello World!"
});
Only the second file needs to be included in the page. Its dependencies (file hello.js in this example) will automatically be loaded and the objects exported from those dependencies will be used to populate the arguments of the callback function.
You can find the related project in Packages JS.
We can use it independently in this way:
var A = A|| {};
A.B = {};
A.B = {
itemOne: null,
itemTwo: null,
};
A.B.itemOne = function () {
//..
}
A.B.itemTwo = function () {
//..
}
In JavaScript there are no predefined methods to use namespaces. In JavaScript we have to create our own methods to define NameSpaces. Here is a procedure we follow in Oodles technologies.
Register a NameSpace
Following is the function to register a name space
//Register NameSpaces Function
function registerNS(args){
var nameSpaceParts = args.split(".");
var root = window;
for(var i=0; i < nameSpaceParts.length; i++)
{
if(typeof root[nameSpaceParts[i]] == "undefined")
root[nameSpaceParts[i]] = new Object();
root = root[nameSpaceParts[i]];
}
}
To register a Namespace just call the above function with the argument as name space separated by '.' (dot).
For Example
Let your application name is oodles. You can make a namespace by following method
registerNS("oodles.HomeUtilities");
registerNS("oodles.GlobalUtilities");
var $OHU = oodles.HomeUtilities;
var $OGU = oodles.GlobalUtilities;
Basically it will create your NameSpaces structure like below in backend:
var oodles = {
"HomeUtilities": {},
"GlobalUtilities": {}
};
In the above function you have register a namespace called "oodles.HomeUtilities" and "oodles.GlobalUtilities". To call these namespaces we make an variable i.e. var $OHU and var $OGU.
These variables are nothing but an alias to Intializing the namespace.
Now, Whenever you declare a function that belong to HomeUtilities you will declare it like following:
$OHU.initialization = function(){
//Your Code Here
};
Above is the function name initialization and it is put into an namespace $OHU. and to call this function anywhere in the script files. Just use following code.
$OHU.initialization();
Similarly, with the another NameSpaces.
Hope it helps.
My habit is to use function myName() as property storage, and then var myName as "method" holder...
Whether this is legitimate enough or not, beat me! I am relying on my PHP logic all the time, and things simply work. :D
function myObj() {
this.prop1 = 1;
this.prop2 = 2;
this.prop3 = 'string';
}
var myObj = (
(myObj instanceof Function !== false)
? Object.create({
$props: new myObj(),
fName1: function() { /* code.. */ },
fName2: function() { /* code ...*/ }
})
: console.log('Object creation failed!')
);
if (this !== that) myObj.fName1(); else myObj.fName2();
You can also do it in a 'vice versa' way to check before object creation which is much better:
function myObj() {
this.prop1 = 1;
this.prop2 = 2;
this.prop3 = 'string';
}
var myObj = (
(typeof(myObj) !== "function" || myObj instanceof Function === false)
? new Boolean()
: Object.create({
$props: new myObj(),
init: function () { return; },
fName1: function() { /* code.. */ },
fName2: function() { /* code ...*/ }
})
);
if (myObj instanceof Boolean) {
Object.freeze(myObj);
console.log('myObj failed!');
debugger;
}
else
myObj.init();
Reference to this: JavaScript: Creating Object with Object.create()
JavaScript doesn’t support namespace by default. So if you create any element(function, method, object, variable) then it becomes global and pollute the global namespace. Let's take an example of defining two functions without any namespace,
function func1() {
console.log("This is a first definition");
}
function func1() {
console.log("This is a second definition");
}
func1(); // This is a second definition
It always calls the second function definition. In this case, namespace will solve the name collision problem.

Nested ES6 classes?

It seems possible to nest a class in a constructor which can then be instantiated from anywhere within the class, is this official?
[EDIT] E.g.,
class C {
constructor() {
class D {
constructor() { }
}
}
method() {
var a = new D(); // works fine
}
}
//var a = new D(); // fails in outer scope
The traceur generated JS https://google.github.io/traceur-compiler/demo/repl.html
$traceurRuntime.ModuleStore.getAnonymousModule(function() {
"use strict";
var C = function C() {
var D = function D() {};
($traceurRuntime.createClass)(D, {}, {});
};
($traceurRuntime.createClass)(C, {method: function() {
var a = new D();
}}, {});
return {};
});
//# sourceURL=traceured.js
No, there are no nested class scopes in ES6, and there is no such thing as private members in the class syntax anyway if you mean that.
Of course you can put a second class as a static property on another class, like this:
class A {
…
}
A.B = class {
…
};
or you use an extra scope:
var C;
{
class D {
constructor() { }
}
C = class C {
constructor() { }
method() {
var a = new D(); // works fine
}
}
}
(There seems to be a bug with traceur as it uses a hoisted var for the class declaration instead of block scope)
With the class field syntax, it will also be possible to write a single expression or declaration:
class A {
…
static B = class {
…
}
};
something like that?
class A {
constructor () {
this.B = class {
echo () {
console.log('I am B class');
}
}
}
echo () {
this.b = new this.B;
this.b.echo();
}
}
var a = new A;
a.echo();
You could use a getter:
class Huffman {
constructor() { /* ... */ }
static get Node() {
return class Node {
constructor() {
var API = this;
API.symbol = 0; API.weight = 0;
return API;
}
};
}
get Node() {
return Huffman.Node;
}
encode() { /* ... */ }
decode() { /* ... */ }
/* ... */
}
// usage
huffman = new Huffman;
new huffman.Node;
new Huffman.Node;
Which in latest Chrome Dev 44.0.2376.0 on Apple 10.10.2 gives in console
new huffman.Node
Node {symbol: 0, weight: 0}
new Huffman.Node
Node {symbol: 0, weight: 0}
In other news, getters are the secret sauce that let's you do a whole bunch of cool things in ES6.
Please Note The above construction breaks instanceof for Node (why? because a whole new class is defined with every get call). To not break instanceof define Node outside of the scope of a single getter, either in the constructor (disabling the Huffman.Node class property and causing instanceof to work within the namespace of a single Huffman instance, and break outside that), or define Node in a sibling or ancestor scope to Huffman (allowing instanceof to work in all scopes below that the one where Node is defined).
When you create a nested child class in a constructor of a parent class, this means every instance of the parent class has its own child class. Typically this is not what you want. Instead you want a child class, which is shared among all instances of the parent class. This means the nested class must be static. This is an example:
class Parent
{
static Child = class Child {
constructor (name) { console.log (`Child: ${name}`); }
}
constructor (...names) {
console.log ('Parent');
this.children = names.map (name => new Parent.Child (name));
}
}
var p = new Parent ('Alice', 'Bob');
console.log (`same type? ${p.children[0].constructor === p.children[1].constructor}`);

Categories

Resources