探讨一下,如有纰漏请指正.
认识在前面:先给出我们讨论的结果
===========================================
javascript是基于原型(prototype-based )的语言.
javascript具有面向对象(Object-Oriented )的编程风格.
变量不一定是对象(undefined,null等就是特例,但是NaN是个对象)
对象一定有值,也有成员(函数,属性)
Object不是顶级的,因为可以delete Object
顶级 的有:
Array Object
Boolean Object
Date Object
Function Object
Math Object
Number Object
RegExp Object
String Object
new 运算符具有一定的魔术性,这个说法我语言上还组织不好.
==========================================
首先我用了词:原型
马上您就知道为什么这么说了.
javascript是基于对象(Object-based )的吗?不是
javascript是面向对象(Object-Oriented )的吗?是 ,要清楚这句话指的是编程方法类似面向对象的编程,但是也有很多不同的地方.
那我们看看Mozilla官方的说法
?javascript是基于原型(prototype-based )的语言.
?
那么我们在描述,研究这个语言的时候就会牵扯到这几个问题.
值和对象 :
var obj={}; var num=9; var str='string' var arr=[];
?很明显上面的几个变量都是一个对象,那变量一定是对象吗 ?
var foo;
?foo是一个变量,但是foo不是对象.对象有个事实上 的特征就是,对象一定有成员 (属性或方法).
?foo就没有任何成员,他的值是undefined ,而undefined 的定义是:
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的魔术性
js是OO的 ECMA-internal说的也很确切
9.constructor;//SyntaxError
这个其实根对不对象没关系 纯粹是因为浮点数跟.运算的词法冲突
有些值类型可以.运算是因为.的时候默认转换成了对应的object
我觉得楼主思想很好 不过有些概念还是要注意一下 这样说比较合适:
目前ECMA没有翻好的中文版
《关于JavaScript的 貌似类(pseudo-classes)----不吐不快》
http://www.iteye.com/topic/85966
谢谢楼上两位.
同时修改了帖子,加入了一些反思的结果
偶E问太差,看不了呀!
谢谢楼上两位.
同时修改了帖子,加入了一些反思的结果
偶E问太差,看不了呀!
Aiming的书是中文的啊
Aiming==周爱民
谢谢楼上两位.
同时修改了帖子,加入了一些反思的结果
偶E问太差,看不了呀!
Aiming的书是中文的啊
Aiming==周爱民
嘻嘻,都说了E文不好了.
Aiming也是E文表示的吧!
javascript的实体书只看过一本,Ajax and REST Recipes
还感觉对自己没有什么帮助(因为偶有自己完整的解决方案),所以就不再买了.
失误呀!
谢谢楼上两位.
同时修改了帖子,加入了一些反思的结果
偶E问太差,看不了呀!
Aiming的书是中文的啊
Aiming==周爱民
嘻嘻,都说了E文不好了.
Aiming也是E文表示的吧!
javascript的实体书只看过一本,Ajax and REST Recipes
还感觉对自己没有什么帮助(因为偶有自己完整的解决方案),所以就不再买了.
失误呀!
为啥我刚说到这本书就有看似枪文的东西出现......
http://www.iteye.com/topic/206407
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; }
<div class='quote_div'>还有个小细节 其实<br/>alert({}.constructor);在FF里也是可以的<br/>{}.constructor;会有问题也是因为词法冲突 {}不在表达式中的时候会被认作语句块(而不是对象构造)<br/></div>
<p><br/><a href='http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Guide:Literals' target='_blank'>Object Literals</a> 中</p>
<div class='quote_title'> 写道</div>
<div class='quote_div'>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 <strong>at the beginning of a statement</strong>. This will lead to an error or not behave as you expect, because the { will be interpreted as the beginning of a block.</div>
<p>?明确了这种用法是会产生错误的.这种用法也就成了语法错误了,也就是你说的解析时候造成<strong>词法冲突</strong></p>
<p>?</p>
<div class='quote_div'>
<div class='quote_title'>csf178 写道</div>
<div class='quote_div'>还有个小细节 其实<br/>alert({}.constructor);在FF里也是可以的<br/>{}.constructor;会有问题也是因为词法冲突 {}不在表达式中的时候会被认作语句块(而不是对象构造)<br/></div>
<p><br/><a href='http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Guide:Literals' target='_blank'>Object Literals</a> 中</p>
<div class='quote_title'>写道</div>
<div class='quote_div'>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 <strong>at the beginning of a statement</strong>. This will lead to an error or not behave as you expect, because the { will be interpreted as the beginning of a block.</div>
<p>?明确了这种用法是会产生错误的.这种用法也就成了语法错误了,也就是你说的解析时候造成<strong>词法冲突</strong></p>
<p>?</p>
</div>
<p>嗯 是这个意思</p>
<p>另外 其实constructor并不是很准 因为constructor可以被修改</p>
<p>在FF中 __proto__ 属性是原型链</p>
<p>var t={__proto__:{a:1,b:2},c:3}</p>
<p>alert(t.a);//1</p>
<p>alert(t.b);//2</p>
<p>alert(t.c);//3</p>
<p>?</p>
<p>在JS中 new和函数的prototype可以看作是提供了一种用原型模拟类的方式 </p>
<p>把拥有同一个原型的一组对象看作属于一个类</p>
<p>?</p>
<div class='quote_div'>lz想要说什么?</div>
<p>我想搞清楚几件事情,经过csf178的讨论,已经清楚了.就几句话.</p>
<p>?</p>
<p>javascript是基于原型(<strong>prototype-based</strong>
)的语言.</p>
<p>javascript具有面向对象(<span style='color: #000000;'><strong>Object-Oriented</strong>
</span>
)的编程风格.</p>
<p><strong>变量不一定是对象(undefined,null等就是特例,但是NaN是个对象)</strong></p>
<p><strong>对象一定有值,也有成员(函数,属性)</strong></p>
<p><strong>Object不是顶级的,因为可以delete Object</strong></p>
<p><strong>顶级</strong>的有:</p>
<p style='background-color: #ffffff; padding-left: 30px;'> <strong><span style='color: #000000;'>Array Object<br/>Boolean Object<br/>Date Object<br/>Function Object<br/>Math Object<br/>Number Object<br/>RegExp Object<br/>String Object</span></strong></p>
<p><strong>new</strong>运算符具有一定的<strong>魔术性,这个说法我语言上还组织不好.</strong></p>
<div class='quote_div'>什么叫顶级的?是不是就是语言内建的叫顶级的?</div>
<p><br/>我也是这么理解的.不过还是用官方的说法比较合适.<br/><a href='http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Guide:Predefined_Core_Objects' target='_blank'>Predefined Core Objects</a></p>
<p>预定义核心对象,</p>
<p>问题是内建这个词没有一个定义,Object是系统一运行就建立的,算不算内建呢?</p>
<p>但是Objcet肯定不算Core Objects,因为官方列表中就没有.</p>
<p>?</p>
<div class='quote_div'>
<div class='quote_title'>soni 写道</div>
<div class='quote_div'>什么叫顶级的?是不是就是语言内建的叫顶级的?</div>
<p><br/>我也是这么理解的.不过还是用官方的说法比较合适.<br/><a href='http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Guide:Predefined_Core_Objects' target='_blank'>Predefined Core Objects</a></p>
<p>预定义核心对象,</p>
<p>问题是内建这个词没有一个定义,Object是系统一运行就建立的,算不算内建呢?</p>
<p>但是Objcet肯定不算Core Objects,因为官方列表中就没有.</p>
<p>?</p>
</div>
<p>好像没什么区别吧 这些都可以delete</p>
<p>Moz写的文档只是把Object单拿出来说了</p>
<p>?</p>
<p>不管怎么说ECMA现在比Moz更官方 ECMA现在是把它们放一起的</p>
<pre name='code' class='js'>delete Object;
alert(typeof Object);
delete Function;
alert(typeof Function);</pre>
<p>?还真不一样.这个世界可真乱呀!</p>
<p>?</p>
但是按照ECMA262的意思 Object Function Array等并非GlobalObject的特权属性 所以应该都可以正确删除
所以虽然标准没有明确的规定 也不应该认为是implementation dependent的
FireFox在此处显然属于实现错误
因为alert(delete Function);是true
说实话 如果你读了SpiderMonkey源码 你会对它有很深的绝望