锁定老帖子 主题:javascript的值,对象,原型
精华帖 (1) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
|
|
---|---|
作者 | 正文 |
发表时间:2008-06-20
探讨一下,如有纰漏请指正. 认识在前面:先给出我们讨论的结果 =========================================== javascript是基于原型(prototype-based )的语言. javascript具有面向对象(Object-Oriented )的编程风格. 变量不一定是对象(undefined,null等就是特例,但是NaN是个对象) 对象一定有值,也有成员(函数,属性) Object不是顶级的,因为可以delete Object 顶级 的有: Array Object new 运算符具有一定的魔术性,这个说法我语言上还组织不好. ========================================== 首先我用了词:原型 马上您就知道为什么这么说了. javascript是基于对象(Object-based )的吗?不是 javascript是面向对象(Object-Oriented )的吗?是 ,要清楚这句话指的是编程方法类似面向对象的编程,但是也有很多不同的地方. 那我们看看Mozilla官方的说法 写道
A prototype-based language, such as JavaScript,
does not make this distinction: it simply has objects. A
prototype-based language has the notion of a prototypical object, an
object used as a template from which to get the initial properties for
a new object. Any object can specify its own properties, either when
you create it or at run time. In addition, any object can be associated
as the prototype for another object, allowing the second object to
share the first object's properties.
javascript是基于原型(prototype-based )的语言.
那么我们在描述,研究这个语言的时候就会牵扯到这几个问题. 值和对象 : var obj={}; var num=9; var str='string' var arr=[]; 很明显上面的几个变量都是一个对象,那变量一定是对象吗 ? var foo; foo是一个变量,但是foo不是对象.对象有个事实上 的特征就是,对象一定有成员 (属性或方法). foo就没有任何成员,他的值是undefined ,而undefined 的定义是: undefined is a property of the global object, i.e. it is a variable in global scope.
The initial value of undefined is the primitive value undefined. undefined 属性是 Global 对象的一个成员,该属性在脚本引擎初始化后可用。如果已声明了一个变量但还没有初始化,那么该变量的值就是 undefined。 也就是说undefined 是一个顶级共有属性,用关键字描述undefined 其实更确切. 现在我们举几个值对象( javascript的其他类型的还有,就不提了) 'isstring'.constructor;//String() true.constructor;//Boolean() 9.0.constructor;//Number();这下对了吧csf178 (9).constructor;//Number();匿名对象 9.constructor;//SyntaxError;经csf178指正,这是浮点数转换造成的语法冲突 [].constructor;//Array() {}.constructor;//fireFox :SyntaxError;IE : Object();注意javascript定义中{}是代码块和对象定义,不是Operator ({}).constructor;//Object();匿名对象 其实值对象这个说法不是很合适.就像上面的前3个确实是值.第4个(9)其实是一个匿名的Number对象 , 但是接下来的两句就有意思了.{}和[]竟然还有如此的区别.而且fireFox和IE实现也不同.(其实从优先级上可以找到一些答案,可惜不同实现有差异) Object Literals 中明确指出{}.xxx这种用法是错误的,所以fireFox出SyntaError是正常的.MS的jscript文档我没有看过,不知道如何解释这个. 那我们如何来评论javascript的这些特性呢? 抛弃面向对象这个说法吧,javascript真的不适合. javascript就是这样的不严格,但是很实用. 经csf178指正后,看来javascript仍旧是OO的.但是是prototype-based 的OO,不是Class-based的OO. 也就是说在javascript里所有的对象都有原型,官方给出的原型 (好在我写这个帖子的时候就是为了要搞清楚这3者的关系) 总结:变量不一定指向对象 (貌似废话),对象一定有值 原型 : 是对象一定有原型constructor 这一点从可以从javascript的constructor的定义中找到根据. 请注意上面例子中所有的constructor都是以函数给出的,其实 原型constructor一定是一个函数形式的定义 javascript:function fun(){}; new fun.constructor;//anonymouse(); (new fun).constructor;//fun(); new fun().constructor;//fun(); (new fun()).constructor;//fun(); 为什么这样?其实这很正常,看看javascript运算符的优先级 就明白了.当然,你不能死照优先级来看语法的合法性,解释起来会很绕嘴的. new Function().constructor;//Function() new Function.constructor;//anonymous() new (Function.constructor);//anonymous() new (Function().constructor);//anonymous() 这几个例子优先级就明显了. (下面的几行是经csf178指正后,反思的结果) 回头再看看官方给出的原型 里面唯独却少了最重要的Object,我们知道Object一定是个对象(javascript里没有class),Object又不在Core里,那Object是从哪里来的呢? Object().constructor;//Object() Object.constructor;//Function() 原来Object是由系统自Function 创建的.怎么证明呢? alert(Object);//Object() delete Object;//true Object;//ReferenceError: Object is not defined 但是你不能delete Function. Function就是一切 (反思到这里了) 因此我们讨论javascript对象的时候不要用class-based OO 的概念去靠(经csf178指正),找原型 constructor 是关键 当然javascript提供了更直观的prototype 属性来实现OO方法的问题. new 这个运算符具有一定的魔术性 function fun1(){this.n=3;} function fun2(){this.n=3;return {};} var foo1=new fun1;//{n:3} var foo2=new fun2;//{} 也就是说原型 constructor 的return值是对new有影响的.这就是new的魔术性 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
发表时间:2008-06-20
prototype-based是OO的一种 wiki上说的很确切
js是OO的 ECMA-internal说的也很确切 9.constructor;//SyntaxError 这个其实根对不对象没关系 纯粹是因为浮点数跟.运算的词法冲突 有些值类型可以.运算是因为.的时候默认转换成了对应的object 引用 我们讨论javascript对象的时候不要用OO的概念去靠
我觉得楼主思想很好 不过有些概念还是要注意一下 这样说比较合适: 引用 我们讨论javascript对象的时候不要用class-based OO的概念去靠
|
|
返回顶楼 | |
发表时间:2008-06-20
去看Aiming的书吧 那本书比较靠谱
目前ECMA没有翻好的中文版 |
|
返回顶楼 | |
发表时间:2008-06-20
|
|
返回顶楼 | |
发表时间:2008-06-20
果然有纰漏.
谢谢楼上两位. 同时修改了帖子,加入了一些反思的结果 引用 ...Aiming的书吧...
偶E问太差,看不了呀! |
|
返回顶楼 | |
发表时间:2008-06-20
achun 写道 果然有纰漏.
谢谢楼上两位. 同时修改了帖子,加入了一些反思的结果 引用 ...Aiming的书吧...
偶E问太差,看不了呀! Aiming的书是中文的啊 Aiming==周爱民 |
|
返回顶楼 | |
发表时间:2008-06-20
csf178 写道 achun 写道 果然有纰漏.
谢谢楼上两位. 同时修改了帖子,加入了一些反思的结果 引用 ...Aiming的书吧...
偶E问太差,看不了呀! Aiming的书是中文的啊 Aiming==周爱民 嘻嘻,都说了E文不好了. Aiming也是E文表示的吧! javascript的实体书只看过一本,Ajax and REST Recipes 还感觉对自己没有什么帮助(因为偶有自己完整的解决方案),所以就不再买了. 失误呀! |
|
返回顶楼 | |
发表时间:2008-06-20
achun 写道 csf178 写道 achun 写道 果然有纰漏.
谢谢楼上两位. 同时修改了帖子,加入了一些反思的结果 引用 ...Aiming的书吧...
偶E问太差,看不了呀! Aiming的书是中文的啊 Aiming==周爱民 嘻嘻,都说了E文不好了. Aiming也是E文表示的吧! javascript的实体书只看过一本,Ajax and REST Recipes 还感觉对自己没有什么帮助(因为偶有自己完整的解决方案),所以就不再买了. 失误呀! 为啥我刚说到这本书就有看似枪文的东西出现...... http://www.iteye.com/topic/206407 |
|
返回顶楼 | |
发表时间:2008-06-21
还有个小细节 其实
alert({}.constructor);在FF里也是可以的 {}.constructor;会有问题也是因为词法冲突 {}不在表达式中的时候会被认作语句块(而不是对象构造) JS词法其实挺烦人的 {}这些还好 正则表达式的 / /语法跟除号的冲突 导致JS成为少数产生式不能完全描述词法的语言 顺便 我补充一点 关于new 可以从SpiderMonkey源码看看比普通的函数调用究竟多了什么 js_InvokeConstructor是new调用函数 js_Invoke就是普通的调用 下面代码第56到第59行是调用js_Invoke 其他部分就是new比普通函数多出来的部分 注释很清楚 JSBool js_InvokeConstructor(JSContext *cx, jsval *vp, uintN argc) { JSFunction *fun; JSObject *obj, *obj2, *proto, *parent; jsval lval, rval; JSClass *clasp, *funclasp; fun = NULL; obj2 = NULL; lval = *vp; if (!JSVAL_IS_OBJECT(lval) || (obj2 = JSVAL_TO_OBJECT(lval)) == NULL || /* XXX clean up to avoid special cases above ObjectOps layer */ OBJ_GET_CLASS(cx, obj2) == &js_FunctionClass || !obj2->map->ops->construct) { fun = js_ValueToFunction(cx, vp, JSV2F_CONSTRUCT); if (!fun) return JS_FALSE; } clasp = &js_ObjectClass; if (!obj2) { proto = parent = NULL; fun = NULL; } else { /* * Get the constructor prototype object for this function. * Use the nominal 'this' parameter slot, vp[1], as a local * root to protect this prototype, in case it has no other * strong refs. */ if (!OBJ_GET_PROPERTY(cx, obj2, ATOM_TO_JSID(cx->runtime->atomState .classPrototypeAtom), &vp[1])) { return JS_FALSE; } rval = vp[1]; proto = JSVAL_IS_OBJECT(rval) ? JSVAL_TO_OBJECT(rval) : NULL; parent = OBJ_GET_PARENT(cx, obj2); if (OBJ_GET_CLASS(cx, obj2) == &js_FunctionClass) { funclasp = ((JSFunction *)JS_GetPrivate(cx, obj2))->clasp; if (funclasp) clasp = funclasp; } } obj = js_NewObject(cx, clasp, proto, parent); if (!obj) return JS_FALSE; /* Now we have an object with a constructor method; call it. */ vp[1] = OBJECT_TO_JSVAL(obj); if (!js_Invoke(cx, argc, JSINVOKE_CONSTRUCT)) { cx->weakRoots.newborn[GCX_OBJECT] = NULL; return JS_FALSE; } /* Check the return value and if it's primitive, force it to be obj. */ rval = *vp; if (JSVAL_IS_PRIMITIVE(rval)) { if (!fun) { /* native [[Construct]] returning primitive is error */ JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_NEW_RESULT, js_ValueToPrintableString(cx, rval)); return JS_FALSE; } *vp = OBJECT_TO_JSVAL(obj); } JS_RUNTIME_METER(cx->runtime, constructs); return JS_TRUE; } |
|
返回顶楼 | |
发表时间:2008-06-21
csf178 写道
还有个小细节 其实
alert({}.constructor);在FF里也是可以的 {}.constructor;会有问题也是因为词法冲突 {}不在表达式中的时候会被认作语句块(而不是对象构造) 写道
An object literal is a list of zero or more pairs of property names and associated values of an object, enclosed in curly braces ({}). You should not use an object literal at the beginning of a statement. This will lead to an error or not behave as you expect, because the { will be interpreted as the beginning of a block.
明确了这种用法是会产生错误的.这种用法也就成了语法错误了,也就是你说的解析时候造成词法冲突
|
|
返回顶楼 | |