本文介绍如何在JavaScript中获取用户自定义类的名称。通过利用对象的constructor属性及其toString()方法,解析函数定义字符串来提取类名。文章提供了__typeof__函数的完整代码示例,并对比了系统类型与自定义类型的返回差异,解决了原生typeof无法区分自定义类的问题。
JavaScript自定义类名获取方法
尽管JavaScript是一种基于对象的语言,但借助其原型(prototype)特性,我们可以构建出非常优秀的面向对象(OO)编程框架。可以参考经典论坛文章'基本上实现 javascript 的 OOP (0423版)'来了解相关实现。
然而,即使我们实现了'类'的概念,JavaScript脚本系统本身并不直接支持识别这种类型。我们无法直接使用脚本系统中的typeof方法来获取自定义类的类型。例如,假设定义了如下'类'JSClass:
function JSClass()
{
this.Attribute1 = null;
this.Attribute2 = null;
this.Method1 = function()
{
// ...
};
this.Method2 = function()
{
// ...
};
this.toString = function()
{
return '[class JSClass]';
};
}
我们创建该类的一个实例:var jsclass = new JSClass();
如果执行alert(typeof(jsclass)),结果仅为'object'。而执行alert(jsclass)时,由于对象实例默认调用toString()方法,我们会得到'[class JSClass]'。虽然可以通过在类中手动定义toString()返回类名,但这种依赖手动维护type字符串的方式并不理想。
因此,我们从类定义本身入手寻找解决方案。JavaScript中的对象(Object)默认实现了toString()方法,而函数对象(Function)的toString()方法会返回该函数的定义源码。利用这一特性,我们可以通过处理类定义字符串来获取类名。
通过对象实例的constructor属性,我们可以获取其构造函数的定义,而构造函数的名称即为JavaScript用户自定义类的类名。以上述例子为例,执行var strFun = jsclass.constructor.toString()后,strFun包含构造函数原始语句定义的字符串(与上述代码块内容一致)。我们需要从strFun中提取'函数名'(即类名),但需注意Function类的实例执行toString()时不会格式化代码。例如,若将JSClass的构造函数写成如下格式:
function
JSClass
(
)
{
this.Attribute1 = null;
this.Attribute2 = null;
// ...
}
执行toString()后,strFun中的代码依然保持这种格式。
__typeof__函数实现
因此,获取类名需要格外小心。以下是__typeof__方法的代码实现:
function __typeof__(objClass)
{
if ( objClass && objClass.constructor )
{
var strFun = objClass.constructor.toString();
var className = strFun.substr(0, strFun.indexOf('('));
className = className.replace('function', '');
return className.replace(/(^\s*)|(\s*$)/ig, '');
}
return typeof(objClass);
}
代码示例与结果分析
示例:
<script language="javascript">
alert(__typeof__(jsclass));
alert(__typeof__(JSClass));
alert(__typeof__(1));
alert(__typeof__([]));
alert(__typeof__({}));
</script>
结果分别为:"JSClass", "Function", "Number", "Array"和"Object"。
这里需要注意两点:一是jsclass与JSClass的区别,jsclass是类实例,而JSClass返回的类型却是Function;二是如果是系统类型,使用typeof得到的类型均为小写(如number、array或object),而使用__typeof__获得的类型名称与类型名匹配,首字母均大写。