浅析JavaScript获得Object对象(自定义对象)的类型名方法

时间:2022-09-13 14:49:29

在写代码的过程中 我们经常会遇到这样一个问题–如何获得某一个对象的类型名。

JavaScript是一种弱类型的语言,通常,我们获取一个对象的类型名会想到typeof方法。但是,当我们想要获得一个自定义类型的兑现的类型名的时候,typeof就有点不够看了。我们先来做一个简单的测试。

<!DOCTYPE html>
<html><head>
<script>
/*一个叫做Student的构造函数*/
function Student (argument) {
// body...
}

/*new一个Student对象*/
var stu = new Student("argument");

console.log(typeof stu);
/*控制台打印的结果是:object*/

</script>
</head>
<body></body></html>

我们虽然知道了stu是一个对象,但是我们却不知道它究竟是一个怎样的对象,所以我们还需要更深层次的处理。

那到底需要怎么做呢?我们知道,在js里,每一个对象都有一个constructor的属性,这个属性直接连接到该对象的构造函数。也就是说,我们可以通过对象的constructor属性来找到它所对应的构造函数。先来看一段代码:

<!DOCTYPE html>
<html><head>
<script>
/*一个叫做Student的构造函数*/
function Student (argument) {
// body...
}

/*new一个Student对象*/
var stu = new Student("argument");

/*这里改成了constructor*/
console.log(stu.constructor);

/*
* 控制台打印结果:
* function Student(argument) {
* // body...
* }
*/


</script>
</head>
<body></body></html>

这个结果是不是很熟悉呢?没错,这个就是我们一开始定义的Student的构造函数。也就是说,对象的constructor属性就是这个对象的构造函数。当我们得到了构造函数之后,得到它的类型名也就轻而易举了,无非就是字符串的操作。

先提供一种最基本的方法:

<!DOCTYPE html>
<html><head>
<script>
/*一个叫做Student的构造函数*/
function Student (argument) {
// body...
}

/*new一个Student对象*/
var stu = new Student("argument");

var str = stu.constructor + '';

var start = str.replace("function","|").indexOf('|');
if(start != -1){
var end = str.replace("function","|").indexOf("(");
if(end != -1){ console.log(str.replace("function","|").slice(start+2,end));
}
}
/*
*控制台返回结果:
*Student
*/

</script>
</head>
<body></body></html>

这样,我们就得到了对象的类型名。

当然,这个方法一看就很臃肿,太丑了。我们对它做一些优化。

    var start = str.replace("function","|").indexOf('|');
var end = str.replace("function","|").indexOf("(");
if(start != -1 && end != -1){
console.log(str.replace("function","|").slice(start+2,end));

}

这样看起来稍微舒服了一点,但是频繁的操作字符串并不是一个好的方法,我们可以通过正则表达式来完成这个操作。

<!DOCTYPE html>
<html><head>
<script>
/*一个叫做Student的构造函数*/
function Student (argument) {
// body...
}

/*new一个Student对象*/
var stu = new Student("argument");

var str = stu.constructor + '';

var r = /function (.+?)\(/;
var name = r.exec(str)[1];
console.log(name);

/*
*控制台打印结果:
*Student
*/

</script>
</head>
<body></body></html>

用正则表达式来处理字符串会更简单一点,但是需要你对正则有一个很好的掌握。

看到这里,有很多人会一脸不屑,我用一个“函数名.name”就可以解决的事你非要洋洋洒洒写这么一堆,看不起你。

的确,js中的函数有一个叫name的属性,可以通过这个属性直接得到函数名,constructor也是一个函数,当然他也就有这个name属性,我们先来看一下:

<!DOCTYPE html>
<html><head>
<script>
/*一个叫做Student的构造函数*/
function Student (argument) {
// body...
}

/*new一个Student对象*/
var stu = new Student("argument");

var str = stu.constructor + '';

console.log(stu.constructor.name);

/*
*控制台输出:
*Student
*/


</script>
</head>
<body></body></html>

哎呀,原来这么简单啊。很遗憾的告诉你,这个name属性,IE8不支持,哈哈哈哈哈哈哈。

为了兼容不同的浏览器,我们需要自己封装一个方法,先来看一个代码:

<!DOCTYPE html>
<html><head>
<script>
/*一个叫做Student的构造函数*/
function Student (argument) {
// body...
}

/*new一个Student对象*/
var stu = new Student("argument");

function getFnName(fn){
/*确保传进来的参数是一个函数*/
if(typeof fn !== "function") return;

if(fn.name){
return fn.name;
}else{
var r = /function (.+?)\(/;
return r.exec(fn + "")[1];
}
}

console.log(getFnName(stu.constructor));

/*
*控制台输出
*Student
*/


</script>
</head>
<body></body></html>

这样就可以通过getFnName方法来得到对象的类型名了,并且适用于各种浏览器。

当然,这个方法还很粗糙,我们做一些修改:

<!DOCTYPE html>
<html><head>
<script>
/*一个叫做Student的构造函数*/
function Student (argument) {
// body...
}

/*new一个Student对象*/
var stu = new Student("argument");

function getFnName(fn){

return typeof fn !== "function" ?
undefined:
fn.name ||
/function (.+?)\(/.exec(fn + "")[1];
}

console.log(getFnName(stu.constructor));

/*
*控制台输出
*Student
*/

</script>
</head>
<body></body></html>

这样这个方法就完成了