3

I'm trying to create a function Vector that takes a number n and returns a type Vector[n]:

let Vector = n => {
    const result = function(...vals) {
        this._data = Array(n).fill(0).map((_, i) => vals[i] || 0)
        Object.assign(this, this._data.reduce((a, c, i) => ({ ...a, ['v' + i]: c }), {}));
    }
    result.prototype.add = function(v) {
        return new result(...this._data.map((x, i) => x + v._data[i]));
    }
    return result;
}

And it works just fine:

 let Vec2 = Vector(2);
 let v1 = new Vec2(0, 1);
 let v2 = v1.add(new Vec2(1, 2))
 console.log(v2);

The logged value looks like this:

 result {_data: Array(2), v0: 1, v1: 3}

It's all working as intended, except that the name of the type is 'result'. I'd rather name it 'Vector2' in this case. How could I do this?

I tried to to create a dynamic name by replacing result with this['Vector' + n] but that resulted in this:

 Vector.(anonymous function) {_data: Array(2), v0: 1, v1: 3}

I also tried assigning result.name and result.prototype.name but neither worked as intended.

Is it possible to rename a dynamically created type in Javascript?

H. Saleh
  • 554
  • 1
  • 5
  • 19
  • Why do you need to rename a type? Are you going to reuse it further in the code? – lolbas Feb 18 '19 at 13:16
  • 1
    Firefox doesn't even log the name; everything's just "Object". – Pointy Feb 18 '19 at 13:19
  • I tried making a dummy object with a computed property name, hoping Chrome would associate the name with the constructor, but that doesn't seem to work. – Pointy Feb 18 '19 at 13:24
  • I suspect the only answer is to use `new Function()` and pass in the function body with the required name. – Alnitak Feb 18 '19 at 13:25
  • `const result = { ["Vector" + n]: (...args) { /* your code */ } }["Vector" + n];` should work as mentioned in the dupe. – Jonas Wilms Feb 18 '19 at 13:34
  • @lolbas mostly for debugging reasons, and yes that's the purpose of the function, to create a type that I can use in the code. @ Pointy I apologize but I should've mentioned- I'm using Chrome. Should I edit the question with these details or do I leave it as is since it's duplicate? – H. Saleh Feb 19 '19 at 10:37

2 Answers2

1

Using new Function() or eval() and enclosing your logic in a template string works.

Check this answer for more information on dynamic function names.

let Vector = n => {
  const name = 'Vec' + n;
  return new Function(`return function ${name}(...vals) {
    this._data = Array(${n}).fill(0).map((_, i) => vals[i] || 0)
    Object.assign(this, this._data.reduce((a, c, i) => ({ ...a, ['v' + i]: c }), {}));
    this.add = function(v) {
      return new ${name}(...this._data.map((x, i) => x + v._data[i]));
    }
  }`)()
}

const Vec2 = Vector(2);
const Vec3 = Vector(3);

const vec2 = new Vec2(0, 1);
const vec3 = new Vec3(0, 1, 2);

console.log(vec2 instanceof Vec2);
console.log(vec3 instanceof Vec3);
console.log(Vec2.name, Vec3.name);
console.log(vec2.add(new Vec2(1, 2)));
console.log(vec3.add(new Vec3(1, 2, 3)));
jo_va
  • 13,504
  • 3
  • 23
  • 47
-1

Your Vector function returns a anonymous function.
If you git it a name, that name will be used by Chrome devtools.

Each environment treats this differently. Consider the following snippet:

const test = function OldName(){}
Object.defineProperty(test, 'name', {value: 'NewName'})
 
console.log(new test())

Chrome logs 'OldName':
enter image description here

Firefox logs 'Object':
enter image description here

Node.js logs 'NewName':
enter image description here

One possible solution is use the Function constructor (new Function()):

const vector = n => new Function(`return function Vector${n}(){}`)()
const test = vector(3)

console.log(new test())

This logs correctly in Chrome.

NemoStein
  • 2,088
  • 2
  • 22
  • 36
  • 2
    and how precisely do you give it a (dynamic) name? – Alnitak Feb 18 '19 at 13:26
  • I don't think it is possible: https://stackoverflow.com/questions/5905492/dynamic-function-name-in-javascript I tried to set the name with `Object.definePropety()` but Chrome still uses the old name. – NemoStein Feb 18 '19 at 13:31
  • 1
    Well, you can use `eval()` or `new Function()`, but that throws performance, security and readability through the window.... – NemoStein Feb 18 '19 at 13:32