javascript的“反射”机制

来源:互联网 发布:知乎用户规模 编辑:程序博客网 时间:2024/04/30 06:07
这里用“反射”这个词仅是一种概念上的借用,且不论下面提到的javascript的特性是否可以被称为“反射”,javascript这种获得对象类型(通过typeof运算)、构造函数(通过观察constructor属性)甚至枚举属性和方法的特性确实为我们学习、研究和使用javascript带来了极大的便利。

在javascript中可以利用for...in方法枚举出对象中所有“可列举”的属性和方法,包括通过prototype机制“继承”的属性和方法

例如:
function classA()
{
    classA.prototype.a = function(){return "a";};
}

function classB()
{
    classB.prototype.b = function(){return "b";};
}classB.prototype = new classA();

var msg = new Array();
var b = new classB();

for (idx in b)
{
    msg.push(idx);
}
alert(msg);

上面这个例子列举出了classB的对象b的所有可列举属性和方法(不可列举的属性方法包括大多数javascript内置对象的固有方法,如Object.isPropertyOf等等,但html对象和dom对象的方法都是可列举的),包括a、b两个成员函数。另外由于javascript中通过关联数组引用和通过函数调用引用无参方法等效(即b["a"]和b.a()都返回字符串"a"),所以将上面例子的循环体改成msg.push(b[idx]);就可以遍历执行b中的所有方法并将结果返回给msg。
   
另外一个有趣的话题是关于instanceof运算的。javascript的instanceof运算足够强大,强大到支持“继承”的判别,如上面那个例子,b instance of classA和b instance of classB的结果都是true。instanceof运算的这个能力正是我们使用“多态”所需要的。

相反地,同强大的instanceof运算相比,javascript的typeof运算则显得有些简陋。它只能识别出string、number等基本类型和object与function类型。这样,要判断对象类型的话,typeof就无能为力。一个比较勉强的解决方案是依靠constructor属性来判断,但是,constructor有个很烦人的问题是,它默认返回的是prototype中的构造函数。结果上面的例子中对象b的constructor竟然返回classA,而不是令人期待的classB,于是,只好在每次继承之时手工修改constructor属性,上面的例子中在classB.prototype=new classA();之后添上classB.constructor = classB。

最后谈到dom对象的问题。在javascript中dom对象和普通对象可以通过判断tagName属性来区别,但是这不是非常好的办法,因为你很难禁止他人在普通对象中定义tagName属性。另外一个比较好的方法是dom对象的constructor属性一般为undefined(同时,显然地,instanceof Object将返回false,这是它们区别其他对象的一个明显特征,当然,前提是必须保证javascript的标准在将来不会扩充到给dom对象赋予确定的constructor和严格的继承机制!最后,我想要说的是,javascript的“反射机制”是强大的,但是也是不完善的,所以在使用的时候需要小心,“常识”往往也容易令人犯错。

结束话题之前发一个稍微封装的“反射”管理类,希望它能够给大家带来一些便利:

function Reflector()
{
        Reflector.getType=function(obj)
        {
                if (obj == null)  //null的类型
                {
                        return null;
                }
                else if (obj instanceof Object)  //普通对象
                {
                        return obj.constructor;
                }
                else if (obj.tagName != null)  //dom对象
                {
                        return obj.tagName;
                }
                else
                {
                        return typeof(obj);
                }
        }
        Reflector.getAttributes=function(obj)
        {
                var methods = new Array();
                for (idx in obj)
                {
                        methods.push(new Type(obj[idx],ClassManager.getType(obj[idx]),idx));
                }
                return methods;
        }
        Reflector.getAttributeNames=function(obj)
        {
                var methods = new Array();
                for (idx in obj)
                {
                        methods.push(idx);
                }
                return methods;
        }
}
//描述类型的类,entity是对象实体,type是对象类型,name是对象名称
function Type(entity, type, name)
{
        this.Entity = entity;
        this.Type = type;
        this.Name = name;
}

原创粉丝点击