JavaScript原型概念说不好理解其实没那么难,说好理解其实也没那么简单,关键是你有没有找到一个合适自己的理解方法。
预备知识:
我想研究js原型的人肯定对js有一定了解,所以基础的知识不再赘述。但是我还要强调一些变态的知识点:
l JavaScript没有类的概念,是基于原型的面向对象。
l function这个关键字一定要理解正确!这不是传统意义上的定义函数的关键字,而是类!一定要把function理解成类!所以,在function a(){}时,其实你是在创建一个functio的实例,a不是函数,而是对象!这正好符合一句真理:“一切皆对象”。
l new关键字也不是传统的new。后边加的是对象,而不是类。
l JavaScript中没有方法,只有属性。
l .表示访问(获取成员属性),()表示执行。比如fun.x()可以理解为:fun这个对象访问了x属性,并执行这个属性。
概念描述(部分内容来自于网络):
在说原型之前,还要先说点别的知识。上边提到function实际上是在创建对象,这时候它充当了两个角色:创建对象、构造函数。JavaScript就是这么规定的,所有的对象在创建时都要有构造函数。还有需要注意的就是new关键字后边接的全是对象,并不是类,new的功能和传统的语言也不一样,因为JavaScript是基于原型的,没有类,所以new不可能完成传统new的功能,那它做什么了呢?我就简单的说一句:new其实就实现了原型机制(具体怎么做的网上资料有的是)。
究竟什么是原型,下边是来自网络的一段话:
“javascript原型是一个对象。 javascript中所有的构造函数都有一个属性,叫prototype,这个属性存放的就是原型对象;访问这个属性通过:函数名.prototype ,从而可以访问到这个原型对象,也可以为这个原型赋值。在原型对象中有一个属性叫constructor,这个constructor指向函数本身。我们可以访问到原型中的这个属性:函数名.prototype.constructor;我们可以为原型对象添加属性并赋值:函数名.prototype.属性名=值;为函数原型添加的属性,都会成为构造函数的属性,从而成为对象的属性。既然对象具有了原型内的属性,说明对象中的这些属性是从原型中继承来的。所以javascript是基于原型的继承的。”
其实原型就是对象的prototype属性指向的对象。对象通过prototype属性继承了“父类”的特性,甚至包括构造函数在内。证明继承了构造函数的例子:
<script type="text/javascript"> function fun1(){alert("我爱中国");}//fun1的构造函数 fun2 = new fun1();//通过fun1创建fun2 fun3 = new fun2();//我们并没有定义fun2的构造函数,但是成功的创建了fun3,说明构造方法也会继承 fun3();//输出“我爱中国” </script>
现在再回过头来看new和function,我们可以通过function和new两种方式创建对象,但两者都要求必须有构造函数,只不过function同时承担了创建对象和构造函数两个职责,而new却要找“父类”的构造函数(系统内部的对象比如Array也有构造函数,这样我们才可以顺利的new,只不过隐藏了)。此时,应该不难理解new实际上是把“父类”作为原型给“子类”的prototype属性。而function是新建,以自己为原型给自己的prototype属性。
这差不多就是JavaScript的原型继承机制了!继续深入,上文提到JavaScript没有方法,只有属性。实际上所有的对象都可以理解为一个属性包,或者说散列数组(key,value),对象只有访问成员的操作。通过“.”指定要访问的属性,通过“()”执行属性(可以理解为方法),JavaScript并不管我们要执行的属性是什么,只负责通过key(属性名)找到相应的value(属性值),所以对象的属性值可以是对象,也可以是数值,是对象的话我们可以用“()”执行,是数值型的话就直接“.”+属性名访问。
原型链:
我们可以自行更改prototype属性,也就是自行设置对象的原型对象。同时,原型继承是链式的。比如,b继承了a,c又继承了b,那么c也继承了a,这样就构成了原型链。原型链的特性是:读的时候从原型链上读,写的时候向自己里面写。大致意思就是:在刚刚abc的例子中,如果在c中访问了一个属性,但是c中没有,会自动去b、a中寻找;但是如果向c中添加属性,那么就直接写在c中。
示例代码:
<script type="text/javascript"> function fun1(){}//创建fun1对象,原型为自身 function fun2(){}//创建fun2对象,原型为自身 fun1.prototype = new Object();//设对象fun1的原型为最底层的系统的Object对象 fun2.prototype = new fun1();//设对象fun2的原型为fun1 Object.prototype.a="a";//给对象Object的原型添加一个数值型a属性 fun = new fun2();//创建一个fun2的对象,继承fun2的所有属性 alert(fun.a);//调用fun2继承来的a属性,实际上调用的Object原型中的a。打印出“a” fun1.prototype.a = "a1";//给fun1的原型(即Object)对象添加一个数值型a属性 alert(fun.a);//调用fun2继承来的a属性,实际上调用的fun1原型(即Object)中的a。打印出“a1” </script>
图解: