howtoweb
howtoweb

Reputation: 359

Get name of constructor in javascript

Is there a way to get the name of the variable made with a constructor?

var TestFunction = function () {
  this.name = ???(); // should return '$testName'
}
var $testName = new TestFunction();

$testName.name should return $testName THX

Upvotes: 1

Views: 75

Answers (1)

T.J. Crowder
T.J. Crowder

Reputation: 1074335

should return '$testName'

That means you're asking how a function can know the name of a variable its result (or rather, the result of new calling it) is about to be assigned to. It can't, there is no mechanism for that, not least because of these possibilities:

a = b = c = d = new TestFunction();
// or
new TestFunction();
// or
foo(new TestFunction());

...but really because fundamentally, the function has no business knowing anything about the context in which it's called other than what the programmer has chosen to tell it by passing as arguments.

Consequently, if you want the function to have that information, you'll need to pass it in, even though that's repetitive:

var $testName = new TestFunction("$testName");

There's a special case (variables at global scope) where you could avoid repeating the name and only pass it as an argument to the function (leaving off the var $testname = part) and then have the function create the "variable," but it would tie the function to global scope, which would fall deep, deep into Bad Idea™ territory. :-)

This is what the special case looks like. Strongly recommend not doing this. (Instead: squint had an excellent suggestion in a comment.)

// STRONGLY RECOMMEND NOT DOING THIS
function TestFunction(name) {
    window[name] = this; // Creates a global
    this.name =name;
}

new TestFunction("$testname");
console.log($testname); // {name: "$testname"}

That works because when you create a property on the global object (which you can access via window on browsers), it creates a global variable.

Please don't do that. :-)


Regarding squint's Proxy idea, it would look something like this:

// Requires ES2016 ("ES6") support in the browser
// Proxy cannot be shimmed, so transpiling won't help
const cookieStore = new Map(); // Our fake storage; you'd use the browser's actual cookie store
function cmAccessor(name, ...args) {
  if (args.length == 0) {
    // Getter; you'd actually use the browser store
    const entry = cookieStore.get(name);
    return entry && entry.value;
  }
  // Setter
  const [value, duration] = args;
  console.log(`Setting '${name}' to '${value}' for ${duration}`);
  // You'd use the real browser store here
  cookieStore.set(name, {value, duration});
}
const CM = new Proxy(Object.create(null), {
  get(target, name) {
    let result = target[name];
    if (!result) {
      result = cmAccessor.bind(null, name);
      target[name] = result;
    }
    return result;
  }
});
CM.cookie1("cookie1 value", 42);
CM.cookie2("cookie2 value", 42);
console.log(CM.cookie1());
console.log(CM.cookie2());

But you'd probably be better off just using a function, a'la jQuery:

// This version is ES5 compatible

const cookieStore = new Map(); // Our fake storage; you'd use the browser's actual cookie store

function CM(name, value, duration) {
  switch (arguments.length) {
    case 0:
      throw new Error("'name' is required");
    case 1:
      // Getter
      // You'd use the browser's real cookie store here
      const entry = cookieStore.get(name);
      return entry && entry.value;
    default:
      // Setter
      console.log("Setting '" + name + "' to '" + value + "' for " + duration);
      // You'd use the real cookie store here
      cookieStore.set(name, {name: name, value: value});
  }
}

// Usage:
CM("cookie1", "cookie1 value", 42);
CM("cookie2", "cookie2 value", 42);
console.log(CM("cookie1"));
console.log(CM("cookie2"));

Upvotes: 6

Related Questions