前言:如果想深入理解Javascript的面向对象编程思想,那么对于原型链的理解将十分重要,由于看了李战老师的<悟透Javascript>,产生了很多疑问,于是带着疑问在网络上查找答案,也翻出了Ecma-262来看了,总算明白了一些东西。
一.类别和对象
在Javascript没有所谓的其他高级语言中的”类”的概念,
所有的”数据”除了基本“类型” 便是对象Object(普通对象object和函数对象function) .
如果从集合论的角度在思考问题,我们可以将所有的这些数据进行分类,那么可以得到如下几类:
Undefined,Null,Boolean,Number,String还有Object
所有的基本数据类型必定属于前面五种类型(Type)之一,而复杂的数据类型只有Object一种.
我们可以举例说明一下,
Undefine={undefined}
Null={null}
Boolean={true,false}
Number={0,1,2,0.1……}
String={’a',’b',’123′,…}
Object={{a:1},function f(){},…}
以上的只是简单的说明,并不严谨.
有了以上的说明我们再来看typeof这个运算符
其实typeof就是根据上面的这些类型来判断并返回结果的
二.内建对象(Build-in Object)
在Javascript语言中有一些内建对象(他们的typeof值为function),其中有Global,Object,Function,Array,String,Boolean,Number,Math,Date,RegExp(注意这里和上面所讲的“类别”是两码事)还有一些其他的错误类,这里暂不一一列举.这些内建对象其实都是构造器,或者说它们都是函数.这里我们可以通过new运算符创建相应的对象.如
var s = new String(’string’);这样得到的是一个字符串对象 ,typeof s 是”object”
而如果没有使用new而是var s=String(’string’);得到的是一个基本类型字符串 ,typeof s得到的是”string”
三.原型Prototype
由于Javascript中没有类,那通过什么来实现面向对象中的继承呢,对,就是原型,原型本身也是对象.
每一个对象都有一个隐式的原型(父原型),而函数对象除了隐式的原型引用外,还有一个显式的原型引用。
在一般情况下,对象的隐式原型是不可以访问的,而函数对象的显式原型可以通过 FunctionName.prototype进行访问,
但在Firefox中你可以通过对象的__proto__属性访问对象的隐式原型。
说了这么多,你可以还是对这两种原型没有理解,我们举个例子吧。
- function Person(name){
- this.name=name;
- }
- alert(Person.prototype);
- alert(Person.prototype.constructor);
- alert(Person.__proto__===Function.prototype);
- alert(Person.constructor);
- var p = new Person('Luke');
- alert(p.prototype);
- alert(p.__proto__===Person.prototype);
- alert(p.constructor);
运行上面的代码我们可以知道,Person这个函数他的显式原型是一个object对象,而这个原型对象的构造器就是Person自己。
我们又可以知道这个函数的哦隐式原型是内置对象Function的显式原型,且我们可以知道Person的构造器是Function函数。
接着我又创建了一个对象p,可以知道如果直接使用prototype是无法访问的,结果为undefined,因为p是一个普通对象,只能在Firefox中通过__proto__来访问其隐式的原型,可以知道其隐式的原型为Person的显式原型。
我这里就很武断的得出一个结论来,当然不一定正确。
一个创建的对象,如果不主动的修改其隐式的原型(当然我们无法修改),那么默认的隐式原型为其constructor的显式原型。
四.原型链
在原型链中Javascript内置的两个初始化函数对象尤为重要,一个就是Function,一个是Object。
下面是一个内建对象原型链的大概图示。
ECMA262规定了一些既定的规则,没有原因,只是为了实现某种目的且自圆其说。