1

I'm not talking about C# but my question relates to it.

C# syntax:

IList<int> list = new List<int>();

list.Add(1);
list.Add(2);
list.Add(3);

foreach (var item in list) Console.WriteLine(item); // 1, 2, 3

IList is an interface while List is a class. And I know that there is no concept interface in javascript, but I can use class instead.

So, js syntax looks like:

let IList = (function () {
    let _T;

    class IList {
        constructor(T) {
            _T = T;
            this[_T] = [];
        }
        Add(item) {
            let _this = this;

            _this[_T].push(item);
        }
        *[Symbol.iterator]() {
            let _this = this;

            let source = _this[_T];

            // it doesn't support forEach method
            // source.forEach(x => yield x);

            for (let s of source) yield s;
        }
    }
    return IList;
}());

let List = (function () {
    class List extends IList {
        constructor(T) {
            super(T);
        }
    }
    return List;
}());

// Usage:

let list = new List('int');

list.Add(1);
list.Add(2);
list.Add(3);

for (let item of list) console.log(item); // 1, 2, 3

I'm stuck with IList class, I don't want to allow creating an instance of that it.

let list = new IList('int'); // throw some exception here

How can I edit it? Thank you!

  • 1
    1. Use TypeScript, which does have interfaces. 2. `throw` an exception in the constructor. – deceze Jun 20 '17 at 11:12
  • @deceze I'm sorry. I just try again by adding an exception inside `IList` constructor. But it throws the exception when I call `super(T)`. –  Jun 20 '17 at 11:18
  • I don't think JavaScript has the concept of a class without an instance... unless you're thinking of a function which hasn't been called yet. – evolutionxbox Jun 20 '17 at 11:19
  • 1
    OP is not really using `IList` like you would use interfaces in TS. Here `IList` is actually an abstract class. – noppa Jun 20 '17 at 11:22
  • I see the only solution for the existing code to forbid creation of IList instance: constructor(T) { if(this.constructor === IList){ throw Error('Creation of IList instance prohibited')} _T = T; this[_T] = []; } – Evgeny Sorokin Jun 20 '17 at 11:27

1 Answers1

0

Throw an exception in the IList constructor if it's invoked directly and not through a super call.

You can get the function that was called with new using new.target (which Babel does not yet handle) or with the better supported this.constructor.

As a side note, your approach also has quite a big flaw with the private variable _T, which is currently shared across all instances of IList. You probably want private properties for the IList instances instead (see: "Private properties in JavaScript ES6 classes").

Full example:

let IList = (function () {
    let _T;

    class IList {
        constructor(T) {
            if (this.constructor === IList) {
             throw new Error('Cannot create an instance of the abstract class IList');
            }
            _T = T;
            this[_T] = [];
        }
        Add(item) {
            let _this = this;

            _this[_T].push(item);
        }
        *[Symbol.iterator]() {
            let _this = this;

            let source = _this[_T];

            // it doesn't support forEach method
            // source.forEach(x => yield x);

            for (let s of source) yield s;
        }
    }
    return IList;
}());

let List = (function () {
    class List extends IList {
        constructor(T) {
            super(T);
        }
    }
    return List;
}());

// This would throw:
// let iList = new IList('int');

let list = new List('int');

list.Add(1);
list.Add(2);
list.Add(3);

// Uncomment this line to break the example because
// the private _T variable will become "string"
// let list2 = new List('string');

for (let item of list) console.log(item); // 1, 2, 3
noppa
  • 3,547
  • 20
  • 21