Тестирование, если что-то является классом в 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() также некоторым из моих функций, не относящихся к классам, которые не являются собственно классами, и затем иметь возможность обрабатывать такие функции, как если бы они были классами, для чего угодно Причина, по которой я мог бы хотеть.