js对象,越玩越有味道,呵呵,下面总结一些知识,供大家参考。
一、js对象起源
首先申明,这里讨论的对象不包括BOM对象(即浏览器对象window、BOM等),只谈论javascript语言本身的对象Object。
先来看一个现象:
alert(Object instanceof Object); //true
alert(Function instanceof Object); //true
alert(Object instanceof Function); //true
alert(Function instanceof Function); //true
由此我们可以知道:
1、对象是对象的实例
2、函数是对象的实例
3、对象是函数的实例
4、函数是函数的实例
呵呵,看到这里是不是晕了,别急,我们慢慢来分析。大家都知道js是基于对象(而不是基于类)和基于原型(protoytpe)的语言,每个函数对象都有一个prototype属性,接下来请看第二个现象:
alert(Object.prototype); //[object Object]
alert(Object.prototype instanceof Object); //false
上面第一句说明Object.prototype是个对象,第二句又说明它不是个对象,这不是自相矛盾了吗?那么这里Object.prototype到底是什么呢?
Object.prototype是所有js对象的源头,在ECMAScript语言规范中是这样写的:
The initial value of Object.prototype is the Object prototype object.
This property has the attributes { DontEnum, DontDelete, ReadOnly }.
The value of the internal [[Prototype]] property of the Object prototype object is null and the value of the internal [[Class]] property is “Object”.
Object.prototype的初始值是the Object prototype object.
它包含一些属性,这些属性是不可枚举、不可删除、只读的。(这些属性以后介绍)
Object prototype object的prototype是null,别的函数对象的prototype是一个Object。
由此我们可知Object.prototype是js原型链的顶层了,这还可从下面例子中得证(SpiderMonkey是firefox等一些浏览器的js引擎,它为我们提供了一个prototype的私有属性__proto__,下面的例子测试这个属性,所以请在以SpiderMonkey为js引擎的浏览器中测试,推荐firefox),先介绍下__proto__是指向父对象的prototype.
function F1(){};
F1.prototype = {
print : function(){
alert("F1.prototype");
}
}
var F2 = new F1();
F2.__proto__.print(); //输出F1.prototype
alert(Object.prototype.__proto__); //输出null
上面的第一个输出说明了__proto__确实指向了父对象的prototype,第二个输出说明Object.prototype没有父对象了,至此我们找到了js原型链的源头,也是js对象的源头。接下来分析Function与Object的关系就比较简单了。
二、Function与Object的关系
首先我们可以把对象分为两类:函数对象(构造器对象)、普通对象。
函数对象包括Function本身,包括Object、String、Number、Boolean,还包括我们定义的函数;
普通对象是除了函数对象外的其他对象如var o = {'attr' : 'test'} , o就是一个普通对象。
要特别强调的是所有的对象(包括函数对象和普通对象),都是由函数对象创建(new)出来的。
创建对象的格式就是
也许有人会问:像上面的o对象就不是由函数对象new的呀? 我们可以看下来这个例子:
var o = {};
alert(o.constructor instanceof Function); //true
alert(typeof o.constructor); //function
上面的例子说明o的构造器(创建出o的)是个函数,其实var o = {'attr' : 'test'}和var o = new Object({'attr' : 'test'})是完全一样的,前面一种写法只是后面写法的简写罢了。看下面的例子:
var o = new Object({'a' : 'test'});
var oo = {'a' : 'test'};
alert(o.a);
alert(oo.a);
alert(oo.toString() === o.toString()); //true
接下来讲下对instanceof方法的理解。首先要强调一点,只有函数对象才有prototype属性,普通对象如果没有特别定义的话是没有prototype的。例子如下:
var f = function(){} ;
var o = {};
alert(f.prototype); //[object Object]
alert(o.prototype); //undefined
o.prototype = {};
alert(o.prototype); //[object Object]
instanceof用法: o1 instanceof o2 返回值 true/false,这里我想强调的是o1可以是任何对象,但是o2只能是函数对象,即使是有定义了prototype属性的普通对象也不行,例子如下:
var f = function(){} ;
var o = {};
o.prototype = {};
alert(o instanceof f); //false
alert(f instanceof o); //浏览器报错
instanceof判断机制,如果o2是o1构造出来的(即 o1 = new o2()),那么毫无疑问,放回true;
当o2不是o1构造出来的时候,是否全部放回false呢? 不是的,请看下面的例子(请在firefox中测试,理由同上,用到了__proto__属性):
var f1 = function(){};
var f2 = function(){};
f2.prototype = new f1(1);
var o1 = new f2();
alert(o1 instanceof f2); //true
alert(o1 instanceof f1); //true
alert(o1 instanceof Object); //true
alert(f2.prototype.__proto__ === f1.prototype); //true
alert(f2.prototype.__proto__.__proto__ === Object.prototype); //true
alert(f1.prototype.__proto__ === Object.prototype); //true
上面全部返回true,即使o1不是f1构造出来的,但是o1 instanceof f1仍然是返回true,最后三行恰好解释了原因,f2.prototype.__proto__指向了f1.prototype,最终指向了Object.prototype。这就很好的解释了为什么js是基于原型链的语言,这也是js实现原型继承的基础。
至此,我们就可以总结一下Function与Object的关系了:
1、所有的Object的实例都是由Function构造出来的,包括Object和Function本身。
2、对象分为两种类型:函数对象和普通对象,Function和Object都是函数对象。
这就是本文开头第一个例子的原因。
哇,终于写完了,第一次写这么长的技术帖,希望对大家有所帮助,有错误在所难免,欢迎大家指正。这周末再总结一些js的对象的一些知识贴上来。下面是一些参考文章的链接,有兴趣的可以去看看。
http://helephant.com/2009/01/javascript-object-prototype/
http://hi.baidu.com/lansesansan/blog/item/43aa41c0d8aa5c170ff47766.html
http://www.jb51.net/article/21804.htm
http://www.cnblogs.com/siemon/archive/2009/08/11/1537095.html
最后祝大家早安哈!!