浏览 2879 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
|
|
---|---|
作者 | 正文 |
发表时间:2011-07-21
我想了一个方式: function isClass(f) { var names = Object.keys(f.prototype) return names.indexOf('constructor') === -1 || names.length > 1 } 这里的假设是,作为构造器的函数会在其prototype上加公共方法。 prototype上默认是有 constructor 属性(指向函数自身)。那么如果keys(prototype上的属性名列表)的长度大于1,意味着作者执行过 f.prototype.xxx = ... ,或者keys不包含constructor属性,意味着作者很可能执行过 f.prototype = { xxx:... } 。这样我们就认为这个函数的意图是被当作构造器(类)来用。 各位如何看? 有什么别的idea么? 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
发表时间:2011-07-21
最后修改:2011-07-21
试了下
function a(){}; alert(isClass(a));//chrome true? prototype判断要不要再向上再找几层,直到Object.prototype |
|
返回顶楼 | |
发表时间:2011-07-21
limu 写道 试了下
function a(){}; alert(isClass(a));//chrome true? prototype判断要不要再向上再找几层,直到Object.prototype 应该是names.indexOf('constructor') === -1这个的问题。 感觉只需要判断prototype key的长度就可以,一般用于class的function肯定都要加prototype的吧。 |
|
返回顶楼 | |
发表时间:2011-07-24
之前的方法有一些小问题,根据标准,constructor属性应是不可enumerable的。所以Object.keys并不会包含constructor属性(感谢jk和luolonghao指出问题)。上面的代码可直接改为:
function isClass(f) { var names = Object.keys(f.prototype) return names.length > 0 } 但考虑旧引擎,则其相关ES5方法是由如es5-shim之类的库补上,行为不是最标准,比如无法知道一个属性是否是enumerable的(这就是jk怀疑的什么引擎会返回constructor,呵呵)。 另外,若f.prototype上存在不可枚举属性,说明什么呢?难道就是不想作为类吗?一个case是我可能希望方法不可枚举。所以可修改如下: function isClass(f) { var names = Object.getOwnPropertyNames(f.prototype) return names.length > 1 || names[0] !== 'constructor' } 这里还存在一个问题。prototype可以是原型继承得来的,上面own properties没有,但是有许多其他继承来的property,那么我们可能需要上溯所有原型(感谢limu提出这个问题)。 不过我直觉上溯并不是好办法,所以我重新考虑我的基本出发点: 原始function(){}的prototype值是一个new Object()结果,且其上定义了constructor属性指向该函数自身。 基本想法是:我们判断当前函数的情况是否和上面一致,如果不一致,则其目的很可能是为了将该函数作为一个类构造器来使用。 所以,最后得到这个版本: // 感谢jk指出isClass这个名字的问题,所以将名称修改为likeContrcutor // 以更好的反映意图。 // 就这个函数的行为而言,最准确的名字或许是isPrototypeModified(), // 不过这样的名字无法反映高阶的意图。 function likeConstructor(f) { return 'prototype' in f && ( Object.getPrototypeOf(f.prototype) !== Object.prototype || Object.getOwnPropertyNames(f.prototype).length > 1 || !('constructor' in f.prototype)) } 'prototype' in f 检测排除了那些没有prototype属性的函数,比如通过Function.prototype.bind调用产生的函数。这样的函数不会被用作constructor。 Object.getPrototypeOf(f.prototype) !== Object.prototype ,如果f.prototype的原型不是Object.prototype,就说明是执行了 f.prototype = new Class() 或者是 f.prototype = Object.create(proto)。因此可以认定f是要被用做constructor。 剩下f.prototype的原型确实是Object.prototype的情形。而Object.prototype上属性的增减与我们的判断无关。这样我们就不必上溯原型链,依旧使用之前的方法。 Object.getOwnPropertyNames(f.prototype).length > 1 ,即如果有1个以上的own properties。 !('constructor' in f.prototype)) ,即如果有1个own property但不是'constructor',或者干脆1个own property也没有。 上述所有情况排除之后剩下的就是: 原始function(){}的prototype值是一个new Object()结果,且其上定义了constructor属性。 唯一没考虑的是仅仅修改了constructor值使其不指向自身的情况。 考虑这样的代码: function F() {} F.prototype = {constructor: A} var x = new F() 看上去也是要作为构造器,可是什么场景下需要把constructor设为另一个函数A呢? (注:我们可以忽略constructor值被设为非函数的情形,因为那样是break了JS的惯例,所以也不必将其视作合理的Constructor) 我想大概是这样的场景,就是给client code一个指示,如果你要创建一个类似对象x的对象,应该调用new A()。这样的场景在涉及元编程时确实存在。 对于这样的情况,我觉得likeConstructor返回false是合理的,因为F在这里扮演的角色只是一个代孕妈妈(代理对象生产这一任务),当然更好的方式实际是用Object.create()。 那么是否要把 f.prototype.constructor === f 作为一个强制约定呢。经过一番思考,我决定不这样做。因为这会导致一些设置B.prototype = new A()后忘记设置B.prototype.constructor = B的代码被认为likeConstructor(B)为false。而这样的可能性是挺大的。无法表明自己是妈妈身份(黑户),和故意放弃妈妈身份(代孕)还是要区别对待的。 以上。欢迎大家继续提意见。 |
|
返回顶楼 | |
发表时间:2011-07-26
感觉没啥意义去判断CONSTRUCTOR把,一般CONSTRUCTOR就是为了能INITIAL些PROPERTY,里面一般就是this.***...新人愚见哈,,本身FUNCTION就是OBJECT,这个很难说吧
|
|
返回顶楼 | |
发表时间:2011-07-28
所有的Function都能用于构造函数吧?
|
|
返回顶楼 | |