Javascript 学习笔记之 对象篇(二) : 原型对象
Javascript是唯一一个被广泛运用的原型式继承的语言,所以理解两种继承方式的差异是需要时间的。
第一个主要差异就是Javascript使用原型链来继承:
functionFoo(){ this.value=42; } Foo.prototype={ method:function(){} }; functionBar(){}
设置Bar的prototype为Foo的对象实例:
Bar.prototype=newFoo(); Bar.prototype.foo='HelloWorld';
确保Bar的构造函数为本身,并新建一个Bar对象实例:
Bar.prototype.constructor=Bar; vartest=newBar();
下面我们来看下整个原型链的组成:
test[instanceofBar] Bar.prototype[instanceofFoo] {foo:'HelloWorld'} Foo.prototype {method:...} Object.prototype {toString:.../*etc.*/}
在上面的例子中,对象test将会同时继承Bar.prototype和Foo.prototype。因此它可以访问定义在Foo中的函数method。当然,它也可以访问属性value。需要提到的是,当newBar()时并不会创建一个新的Foo实例,而是重用它原型对象自带的Foo实例。同样,所有的Bar实例都共享同一个value属性。我们举例说明:
test1=newBar(); test2=newBar(); Bar.prototype.value=41; test1.value//41 test2.value//41
原型链查找机制
当访问一个对象的属性时,Javascript会从对象本身开始往上遍历整个原型链,直到找到对应属性为止。如果此时到达了原型链的顶部,也就是上例中的Object.prototype,仍然未发现需要查找的属性,那么Javascript就会返回undefined值。
原型对象的属性
尽管原型对象的属性被Javascript用来构建原型链,我们仍然可以值赋给它。但是原始值复制给prototype是无效的,如:
functionFoo(){} Foo.prototype=1;//noeffect
这里讲个本篇的题外话,介绍下什么是原始值:
在Javascript中,变量可以存放两种类型的值,分别是原始值和引用值。
1.原始值(primitivevalue):
原始值是固定而简单的值,是存放在栈stack中的简单数据段,也就是说,它们的值直接存储在变量访问的位置。
原始类型有以下五种型:Undefined,Null,Boolean,Number,String。
2.引用值(referencevalue):
引用值则是比较大的对象,存放在堆heap中的对象,也就是说,存储在变量处的值是一个指针 pointer,指向存储对象的内存处。所有引用类型都集成自Object。
原型链性能问题
如果需要查找的属性位于原型链的上端,那么查找过程对于性能而言无疑会带来负面影响。当在性能要求必要严格的场景中这将是需要重点考虑得因素。此外,试图查找一个不存在属性时将会遍历整个原型链。
同样,当遍历一个对象的属性时,所有在原型链上的属性都将被访问。
总结
理解原型式继承是写较为复杂的Javascript代码的前提,同时要注意代码中原型链的高度。当面临性能瓶颈时要学会将原型链拆分开来。此外,要将原型对象prototype和原型__proto__区分开来,这里主要讨论原型对象prototype就不阐述关于原型__proto__的问题了,