Тестирование, если что-то является классом в javascript

Привет всем, я пытаюсь проверить, если аргумент, переданный в мою функцию, является именем класса, поэтому я могу сравнить его с другими классами с помощью instanceof.

Например:

function foo(class1, class2) {
  // Test to see if the parameter is a class.
  if(class1 is a class)
  {
    //do some kind of class comparison.
    if(class2 is a class)
    {
       if(class1 instanceof class2)
       {
          //...
       }
    }
    else
    {
       //...
    }
  }
  else
    //...
}

Возможно ли это? У меня возникли проблемы с ответом googleing.

Ответ 1

В javascript действительно нет такого понятия, как "класс" - все, кроме примитивов, является объектом. Даже функции являются объектами.

instanceof РАБОТАЕТ с функциями, хотя. Проверьте эту ссылку.

function Car(make, model, year)
{
  this.make = make;
  this.model = model;
  this.year = year;
}
var mycar = new Car("Honda", "Accord", 1998);
var a = mycar instanceof Car;    // returns true
var b = mycar instanceof Object; // returns true

Ответ 2

Теперь, когда у нас есть собственные реализации ES6, существуют "реальные классы". Это в значительной степени синтаксический сахар для прототипного наследования, как и функции конструктора, но есть тонкие различия, и они не являются полностью взаимозаменяемыми.

До сих пор единственным способом, который я нашел, является получение .toString() функции конструктора объектов-прототипов и проверка, начинается ли она с class ИЛИ, если у объекта есть конструктор и .toString() этого запускает с class.

Обратите внимание, что если ваш код скомпилирован (то есть: большинство настроек Babel или TypeScript), тогда во время выполнения возвращается function... вместо class... (поскольку классы передаются в конструкторские функции).

function isClass(obj) {
  const isCtorClass = obj.constructor
      && obj.constructor.toString().substring(0, 5) === 'class'
  if(obj.prototype === undefined) {
    return isCtorClass
  }
  const isPrototypeCtorClass = obj.prototype.constructor 
    && obj.prototype.constructor.toString
    && obj.prototype.constructor.toString().substring(0, 5) === 'class'
  return isCtorClass || isPrototypeCtorClass
}

Это будет работать только в родных средах (Chrome, Firefox, Edge, node.js и т.д.), которые внедрили class для кода, который не был передан на function.

Использование:

class A {}
class B extends A {}
isClass(A) // true
isClass(new A()) // true
isClass(B) // true
isClass(new B()) // true

function C() {}
isClass(C) // false
isClass(new C()) // false
isClass({}) // false
isClass(Date) // false
isClass(new Date()) // false

//These cases return 'true' but I'm not sure it desired
isClass(Object.create(A)) // true    
const x = {}
Object.setPrototypeOf(x, A)
isClass(x) // true

Если есть лучший способ, я хотел бы знать, что это такое.

Ответ 3

JavaScript не имеет классов. Он имеет функции, которые при использовании с new могут использоваться для создания экземпляров объекта. Поэтому вы действительно хотите проверить, является ли функция class2 функцией. Существует множество способов достижения этого; текущая (1.3) реализация isFunction() в jQuery выглядит следующим образом:

isFunction: function( obj ) {
    return toString.call(obj) === "[object Function]";
},

... Но см. здесь краткое изложение различных методов: Лучший способ тестирования функции в JavaScript?

Ответ 4

Здесь быстрый и грязный способ определить, есть ли у вас класс или функция.

function myFunc() { };
class MyClass() { };

Object.getOwnPropertyNames(myFunc);
// -> [ 'length', 'name', 'arguments', 'caller', 'prototype' ]

Object.getOwnPropertyNames(MyClass);
// -> [ 'length', 'prototype', 'name' ]

Итак, мы знаем, что у нас есть функция, а не класс, если arguments - это имя свойства:

Object.getOwnPropertyNames(myFunc).includes('arguments');
// -> true

Object.getOwnPropertyNames(MyClass).includes('arguments');
// -> false

Функции со стрелками и функции aysnc не будут иметь имени свойства arguments или prototype. Более полный пример может выглядеть следующим образом (при условии, что мы знаем, что входные данные могут быть только функцией или классом):

function isFunction(funcOrClass) {
  const propertyNames = Object.getOwnPropertyNames(funcOrClass);
  return (!propertyNames.includes('prototype') || propertyNames.includes('arguments'));
}

function isFunction(funcOrClass) {
  const propertyNames = Object.getOwnPropertyNames(funcOrClass);
  return (!propertyNames.includes('prototype') || propertyNames.includes('arguments'));
}

console.log('class isFunction?', isFunction(class A {}));
console.log('function isFunction?', isFunction(function() {}));
console.log('async function isFunction?', isFunction(async function() {}));
console.log('arrow function isFunction?', isFunction(() => {}));

Ответ 5

Я считаю, что это работает для меня.

if(typeof type === 'function' && type.name !== 'Object'){
   // This is a class.
}

Я работаю с машинописью, и я был в состоянии использовать это, чтобы последовательно фильтровать по классам.

Ответ 6

Я не нашел 100% верного способа выяснить, является ли что-то классом, а не функцией. Принятый ответ выше работает в большинстве случаев, но если кто-то переопределит метод toString() своего класса, в этом случае он может сломаться. Зачем им когда-либо переопределять toString()? Я не знаю, спросите их, если они все еще рядом :-)

Поэтому вместо этого я использовал подход определения этой функции:

function isClass(v)
{ if (typeof v !== "function")
  { return false;
  }
  if ( typeof v.isClass === "function" &&
       v.isClass()
     )
  { return true;
  }
}

Это означает, что я могу пометить свои собственные классы как классы, которые я распознаю как классы, дав им статический метод isClass(), который возвращает true. Если такие классы имеют подклассы, подклассы наследуют метод и, таким образом, автоматически распознаются как "классы".

Если мне нужно работать с другими классами, у которых нет этого метода, я мог бы сначала создать подкласс их класса, чтобы мой подкласс был похож на их класс, за исключением того, что у него также есть isClass() -method.

Я надеюсь, что следующая версия EcmaScript восполнит это отсутствие стандартизированного решения, но пока это лучшее, что я могу сделать.

Это дает дополнительное преимущество, заключающееся в том, что я мог бы на самом деле дать метод isClass() также некоторым из моих функций, не относящихся к классам, которые не являются собственно классами, и затем иметь возможность обрабатывать такие функции, как если бы они были классами, для чего угодно Причина, по которой я мог бы хотеть.