Skip to content

Instantly share code, notes, and snippets.

@dfkaye
Created February 25, 2023 21:09
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dfkaye/06f7078b157117545fa70faa02957299 to your computer and use it in GitHub Desktop.
Save dfkaye/06f7078b157117545fa70faa02957299 to your computer and use it in GitHub Desktop.
detect whether something is a class in JavaScript, not just a function; warning: this is not tamper-proof
// 25 February 2023
// detect whether something is a class in JavaScript, not just a function.
// warning: this is not tamper-proof.
// @webreflection figured this out
// https://stackoverflow.com/questions/30758961/how-to-check-if-a-variable-is-an-es6-class-declaration/75567955#75567955
// The test?
// The variable is typeof function and its prototype field is not writable.
// Example with a function
var F = function () {}
console.log(typeof F);
// "function"
console.log(Object.getOwnPropertyDescriptor(F, "prototype").writable);
// true
// Example with a class
var A = class {}
console.log(typeof A);
// "function"
console.log(Object.getOwnPropertyDescriptor(A, "prototype").writable);
// false
///////////////////////////////////////
// So let's make a function to do that.
///////////////////////////////////////
function isClass(Class) {
return (
typeof Class == 'function'
&& !Object.getOwnPropertyDescriptor(Class, "prototype").writable
);
}
/* test it out */
console.log("class A is a class:", isClass(A));
// class A is a class: true
console.log("function F is a class:", isClass(F));
// function F is a class: false
console.log("NaN is a class:", isClass(NaN));
// NaN is a class: false
// However, this isn't tamper-proof.
// We can spoof this behavior by overwriting the prototype property descriptor...
var fake = function () {};
Object.defineProperty(fake, "prototype", {
value: fake.prototype,
writable: false
});
console.log("fake is a class:", isClass(fake));
// fake is a class: true
// ...or via freezing:
var frozen = Object.freeze(function () {});
console.log("frozen is a class:", isClass(frozen));
// frozen is a class: true
@WebReflection
Copy link

WebReflection commented Feb 26, 2023

you don't need value there, Object.defineProperty(fake, "prototype", {writable: false}); is enough, as defineProperty and defineProperties change descriptors values already present, so value is unnecessary, as it won't be changed.

that being said, you basically repeated what Babel does when targeting ES5 to indeed hints and represent ES2015 classes as dictated by specs ... if you taint functions in the wild your code will just break, if you use my suggested function it will work even with transpiled classes so ... I am not sure where you are going with this argument 🤷

@WebReflection
Copy link

also, form my SO answer, this is not there by accident:

basically there is no correct answer to this question, just a list of compromises and targets to consider.

enjoy your Sunday 👋

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment