- 浏览: 961269 次
- 性别:
- 来自: 上海
文章分类
最新评论
-
sscsacdsadcsd:
mike8625 写道react还要自己的一些标签 还得编译 ...
对于React体系的一点想法 -
mike8625:
说的都是给大公司听的,国内很多还是小公司,做个小项目, 说实话 ...
关于国内前端和JS技术发展的乱想 -
mike8625:
react还要自己的一些标签 还得编译 编译吧浏览器端说还慢 ...
对于React体系的一点想法 -
u012814086:
下意识想到了Golang
JavaScript语句后应该加分号么? -
xueduanyang:
我是水羊,年轻的时候觉得只要有好斧子就能做成好产品,各种产品都 ...
关于国内前端和JS技术发展的乱想
前提是不要求做什么特殊标记。只是最大可能的猜测函数的作用大概是当“类”使用。
我想了一个方式:
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么?
【7月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属性指向该函数自身。
基本想法是:我们判断当前函数的情况是否和上面一致,如果不一致,则其目的很可能是为了将该函数作为一个类构造器来使用。
所以,最后得到这个版本:
'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。而这样的可能性是挺大的。无法表明自己是妈妈身份(黑户),和故意放弃妈妈身份(代孕)还是要区别对待的。
以上。欢迎大家继续提意见。
没有this还哪里有新对象呀!这咋做构造器呢?
指 bind 的参数 thisArg没用
没有this还哪里有新对象呀!这咋做构造器呢?
上面的测试没有成功,Object.getOwnPropertyNames(f.prototype)返回["getName"].length=1而不是>1.
看起来('constructor' in f.prototype)这句即使constructor不能enumerable但这个语句依然返回真.
别的浏览器没有试过,在chrome下,按你的思路似乎这最后的语句应该改成,来说明只有一个OwnProperty且不是constructor:!(f.prototype.hasOwnProperty("constructor")).
是这样么?
==============
这是个小问题,如果没有prototype上的动作应该直接var p2 = {name:"a"}.
但也不能说这个写法完全没有意义.一方面,可能后续会添加OwnProperty,
另一方面,console.log(p1)控制台会明确告诉p1是一个Person,而log(p2)则肯定是Object.
之所以测试了这个,你在最初提出这个问题的时候,我在想constructor的一个特点,构造函数体内常常有this引用.而普通function一般不会.
我想了一个方式:
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么?
【7月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。而这样的可能性是挺大的。无法表明自己是妈妈身份(黑户),和故意放弃妈妈身份(代孕)还是要区别对待的。
以上。欢迎大家继续提意见。
评论
11 楼
enix2212
2011-07-27
instaceof 不能么?
10 楼
yiminghe
2011-07-25
hax 写道
yiminghe 写道
bind 构造器还是挺好玩的,this 不起作用,但是参数还是可以的
没有this还哪里有新对象呀!这咋做构造器呢?
指 bind 的参数 thisArg没用
9 楼
hax
2011-07-25
yiminghe 写道
bind 构造器还是挺好玩的,this 不起作用,但是参数还是可以的
没有this还哪里有新对象呀!这咋做构造器呢?
8 楼
yiminghe
2011-07-25
bind 构造器还是挺好玩的,this 不起作用,但是参数还是可以的
7 楼
yiminghe
2011-07-25
bind 的为啥不能作为构造器(不推荐?),mdc上有个构造器的例子
6 楼
hax
2011-07-25
光写代码,还没有来得及测试,呵呵。可能in的那个判断是有问题,我再推敲推敲。
这是个小问题,如果没有prototype上的动作应该直接var p2 = {name:"a"}.
但也不能说这个写法完全没有意义.一方面,可能后续会添加OwnProperty,
另一方面,console.log(p1)控制台会明确告诉p1是一个Person,而log(p2)则肯定是Object.
之所以测试了这个,你在最初提出这个问题的时候,我在想constructor的一个特点,构造函数体内常常有this引用.而普通function一般不会.
你说的这个情况,一开始就考虑过。如果不修改prototype,全部在构造器里通过this引用添加属性,确实也是可行的,检测不出来。但这样的构造器本质上就无法准确检测出来,因为它和一般的method无法区分(method里有都有this引用),除非你认为函数名大写可以表明它是“构造器”,这又回到了命名约定的路子上去了。
或许还是应该把名字改回为likeClass()?这样可认为不带有prototype的不like Class?
limu 写道
function Person(name){ this.name = name; } alert(likeConstructor(Person));//chrome false var p1 = new Person("a");
这是个小问题,如果没有prototype上的动作应该直接var p2 = {name:"a"}.
但也不能说这个写法完全没有意义.一方面,可能后续会添加OwnProperty,
另一方面,console.log(p1)控制台会明确告诉p1是一个Person,而log(p2)则肯定是Object.
之所以测试了这个,你在最初提出这个问题的时候,我在想constructor的一个特点,构造函数体内常常有this引用.而普通function一般不会.
你说的这个情况,一开始就考虑过。如果不修改prototype,全部在构造器里通过this引用添加属性,确实也是可行的,检测不出来。但这样的构造器本质上就无法准确检测出来,因为它和一般的method无法区分(method里有都有this引用),除非你认为函数名大写可以表明它是“构造器”,这又回到了命名约定的路子上去了。
或许还是应该把名字改回为likeClass()?这样可认为不带有prototype的不like Class?
5 楼
limu
2011-07-24
----汗:有句话乱了,重新发下----
按你的思路似乎最后一个语句应该改成.
!(f.prototype.hasOwnProperty("constructor")).
来说明只有一个OwnProperty且不是constructor.
是这样不?
按你的思路似乎最后一个语句应该改成.
!(f.prototype.hasOwnProperty("constructor")).
来说明只有一个OwnProperty且不是constructor.
是这样不?
4 楼
limu
2011-07-24
function Person(name){ this.name = name; } Person.prototype = { getName : function(){ return this.name; } } //Person.prototype.constructor = Person;//注释掉这一行 alert(likeConstructor(Person));//chrome false
上面的测试没有成功,Object.getOwnPropertyNames(f.prototype)返回["getName"].length=1而不是>1.
看起来('constructor' in f.prototype)这句即使constructor不能enumerable但这个语句依然返回真.
别的浏览器没有试过,在chrome下,按你的思路似乎这最后的语句应该改成,来说明只有一个OwnProperty且不是constructor:!(f.prototype.hasOwnProperty("constructor")).
是这样么?
==============
function Person(name){ this.name = name; } alert(likeConstructor(Person));//chrome false var p1 = new Person("a");
这是个小问题,如果没有prototype上的动作应该直接var p2 = {name:"a"}.
但也不能说这个写法完全没有意义.一方面,可能后续会添加OwnProperty,
另一方面,console.log(p1)控制台会明确告诉p1是一个Person,而log(p2)则肯定是Object.
之所以测试了这个,你在最初提出这个问题的时候,我在想constructor的一个特点,构造函数体内常常有this引用.而普通function一般不会.
3 楼
jkisjk
2011-07-21
isClass看起来是个严谨的方法,但是由于js里Class是个没有规范的模糊的东东,所以叫isClass让人不大明白目的是什么。
----如果没Class基类,这名字含义模糊;如果已有Class基类,判断也不应该是这么写。
可以换一个没歧义的名字,如
var hasProtoProperty=function(f){
for(var i in f.prototype) return true;
return false;
};
alert(hasProtoProperty(hasProtoProperty));
alert(hasProtoProperty(document.body.constructor));
----如果没Class基类,这名字含义模糊;如果已有Class基类,判断也不应该是这么写。
可以换一个没歧义的名字,如
var hasProtoProperty=function(f){
for(var i in f.prototype) return true;
return false;
};
alert(hasProtoProperty(hasProtoProperty));
alert(hasProtoProperty(document.body.constructor));
2 楼
jkisjk
2011-07-21
js里Class是个模糊的东东,还没有规范起来。isClass
1 楼
jkisjk
2011-07-21
keys得不到'constructor'吧,莫非是什么神奇的浏览器?
发表评论
-
论ES6模块系统的静态解析
2013-03-14 04:56 15875本文是Dave Herman的《Stati ... -
如何创建一个JavaScript裸对象
2012-08-27 02:11 8050所谓裸对象,即 naked object ,是指没有原型(sp ... -
JavaScript语句后应该加分号么?
2012-06-19 03:10 14378这是一个老生常谈的问 ... -
shim是应该抛异常还是应该fail silently?
2011-08-11 17:26 5580玉伯发布了es5-safe模块 ... -
7月30日的广州演讲视频和Slides
2011-08-01 23:38 31757月30日在W3CTech广州站活动上的演讲,题目是:ECMA ... -
关于国内前端和JS技术发展的乱想
2011-07-19 18:53 33267玉伯在我的一条微博后面写了一些(和主题不是很相关但)非常值得思 ... -
Module与Trait的比较
2011-08-12 12:50 4004最近我多次提及module和trait。 粗看,我们可以发现 ... -
如何将let结构(block scope)转换到当前的JavaScript代码
2011-07-12 17:24 3006本文是对如何将let结构转换到ES3代码的补充。 首先,原文 ... -
JavaScript的未来方向之观察
2011-07-12 02:53 8372最近每次去杭州,都有 ... -
我为什么力挺NodeJS
2011-07-04 00:27 0之前在参加CNodeJS社区在 ... -
JS之父再谈JS历史(续完)
2010-12-31 04:20 3438又到年底,我觉得是时候还债了。自开blog来,我出了不少“太监 ... -
我为什么是DC黑续,兼答Tin
2010-04-27 14:29 0我同意安全是一个重要问题。我不同意的是把所谓安全放到凌驾于其他 ... -
我为什么是DC黑─Why I disagree with Douglas Crockford
2010-04-26 17:51 11015参加完了QCon北京大会, ... -
写对正则:一行代码,速度差50倍
2009-05-12 03:43 60132009-05-11 A lesson of ... -
JavaScript的EOS(分号)问题
2009-05-08 16:24 5777在http://bbs.51js.com/viewthre ... -
JavaScript五大关键字
2009-05-06 17:53 4767近期做语法高亮项目的副产品,是统计了一下几个主流JS工具包中各 ... -
curry和partial的差别
2009-03-28 00:15 371351js上asfman翻译了http://ejohn.org/ ... -
Eval is Evil , With evil too
2009-03-27 18:39 0with的问题: 2009-3-27 17:12:40 ... -
IE全局变量的Dissociative Identity Disorder(人格分裂症)
2009-03-16 02:47 14736最近,小麦提出了一个疑惑: 小麦 写道最后介绍一个我也搞不明白 ... -
JScript下Array对象的性能问题
2009-02-14 02:51 4003今天看了微软JScript官方blog上去年的两篇文章: ht ...
相关推荐
构建一个类Point,它提供两个公有的构造函数,一个没有参数的Point构造函数和一个有两个double参数的构造函数。另外在该类中提供一个静态方法计算两个点的直线距离,传入参数为两个Point类实例。然后设计一个测试类...
3. **代码可扩展性和安全性**:如果一个类可能作为其他类的基类,则应将其析构函数声明为虚函数。这不仅可以确保代码的安全性,还可以提高代码的可扩展性,允许未来添加更多的派生类而无需修改现有代码。 ### 实例...
- 这是因为构造函数调用的顺序是从基类到派生类,而在构造函数中调用虚函数时,虚拟表(VTable)中的指针还未被更新为最终派生类的版本,导致调用的总是当前类的函数。 4. **潜在的安全问题** - 如果允许在构造函数...
题目:建立一个名为Student的类,该类有以下几个私有成员变量:学生姓名、学号、性别、年龄。还有以下两个成员函数:一个用于初始化学生姓名、学号、性别和年龄的构造函数,一个用于输出学生信息的函数。编写一个...
本文将详细解析一个简单的C++类`cPerson`的实现,重点关注其构造函数、析构函数以及拷贝构造函数。 ### 构造函数 构造函数是在创建类的对象时自动调用的一种特殊成员函数,主要用于初始化对象的数据成员。`cPerson...
例如,考虑`Location`类,它定义了三个构造函数:无参构造函数、一个接受单个整数参数的构造函数以及一个接受两个整数参数的构造函数。 ```cpp class Location { private: int X, Y; public: Location(); // 无参...
接下来,定义了一个派生自`A`的类`B`,它增加了一个新的整型成员变量`y`,并且也提供了三个构造函数:默认构造函数、带一个整型参数的构造函数以及同时接受两个整型参数的构造函数。最后一个构造函数调用了基类的...
而另一个构造函数,由于带有参数,可视为有参构造函数或用户定义的构造函数,用于创建对象时可以为成员变量提供特定的值。 Student类中还包含了一个复制构造函数,它允许程序员创建一个新对象作为现有对象的副本。...
构造函数可以被重载,这意味着一个类可以有多个构造函数,但每个构造函数的参数列表必须不同。 在提供的代码示例中,定义了一个名为`Student`的类,其中包含了一个构造函数: ```cpp Student(int n, string nam, ...
以上就是定义一个`complex`复数类的基本步骤,包括构造函数、拷贝构造函数和打印功能。在实际项目中,我们可能还需要为这个类添加其他功能,比如复数的加法、减法、乘法和除法等操作,以及重载相应的运算符,以提高...
在C++编程中,"没有可用的复制构造函数或复制构造函数声明"是一个常见的错误,通常出现在尝试复制一个对象,而该对象的类没有定义复制构造函数时。在这个特定的情境中,问题出在一个名为`CArray, int>`的自定义数组...
5. **默认构造函数**: 如果类中未明确定义任何构造函数,编译器会自动生成一个默认构造函数,该构造函数无参数且不执行任何操作。如果类中有至少一个用户定义的构造函数,那么编译器将不再提供默认构造函数。 **...
在给出的代码示例中,定义了一个名为F的构造函数,该构造函数设置了两个属性:name和age。当通过new F()创建了一个实例f之后,实例f就拥有了这两个属性,分别是'Jack'和18。 通过console.log(f)输出f对象,可以...
在C++中,每个类都必须有一个默认的构造函数,如果没有提供构造函数,那么C++将自动提供一个默认的构造函数。构造函数的主要作用是将类对象的成员变量初始化为默认值或指定值。 在C++中,构造函数的定义必须和类名...
如果我们不提供任何自定义的构造函数,编译器会为每个类生成一个默认的构造函数,该构造函数不执行任何操作。然而,当我们在类中定义了构造函数,即使是无参数的,编译器就不会再提供默认构造函数,因此,`Student a...
- **自动调用**:每当创建一个类的新对象时,构造函数会被自动调用。 #### 二、构造函数的种类 构造函数主要分为以下几种类型: 1. **无参数构造函数**: - **定义**:当一个类没有定义任何构造函数时,编译器会...
构造函数可以被重载,即在同一个类中可以有多个具有不同参数列表的构造函数。 静态块(`static`)是在类定义中包含的一段特殊的代码块,它在类加载时执行,而不是在对象创建时执行。静态块常用于初始化静态变量或...
在实验中,我们将设计和实现一个CPoint类,该类具有两个整型成员变量x和y,另外还具有一个输出函数Print()用来输出横坐标和纵坐标。我们还将设计和实现一个CPerson类,该类具有一个字符串成员变量name和一个整型成员...
- **多个构造函数**:尽管Python不支持多重构造函数的概念(即一个类不能有多个不同签名的构造函数),但我们可以通过提供默认参数值来模拟多重构造函数的效果。例如,可以在构造函数中设置某些参数的默认值,从而...
java代码-使用java解决在Person类的基础上,添加一个带参数的构造函数,参数分别为姓名,性别,年龄的源代码 ——学习参考资料:仅用于个人学习使用!