Javascript
并无类继承模型,而是使用原型对象 prototype
进行原型式继承。
尽管人们常常将此看作是 Javascript
的一个缺点,然而事实上,原型式继承比传统的类继承模型要更增强大。举个例子,在原型式继承顶端构建一个类模型很简单,然而反过来则是个困可贵多的任务。Javascript
是惟一一个被普遍运用的原型式继承的语言,因此理解两种继承方式的差别是须要时间的。git
第一个主要差别就是 Javascript
使用原型链来继承:github
function Foo() { this.value = 42; } Foo.prototype = { method: function() {} }; function Bar() {}
设置 Bar
的 prototype
为 Foo
的对象实例:segmentfault
Bar.prototype = new Foo(); Bar.prototype.foo = 'Hello World';
确保 Bar
的构造函数为自己,并新建一个 Bar
对象实例:ide
Bar.prototype.constructor = Bar; var test = new Bar();
下面咱们来看下整个原型链的组成:函数
test [instance of Bar] Bar.prototype [instance of Foo] { foo: 'Hello World' } Foo.prototype { method: ... } Object.prototype { toString: ... /* etc. */ }
在上面的例子中,对象 test
将会同时继承 Bar.prototype
和 Foo.prototype
。所以它能够访问定义在 Foo
中的函数 method
。固然,它也能够访问属性 value
。须要提到的是,当 new Bar()
时并不会建立一个新的 Foo
实例,而是重用它原型对象自带的 Foo
实例。一样,全部的 Bar
实例都共享同一个 value
属性。咱们举例说明:性能
test1 = new Bar(); test2 = new Bar(); Bar.prototype.value = 41; test1.value //41 test2.value//41
当访问一个对象的属性时,Javascript
会从对象自己开始往上遍历整个原型链,直到找到对应属性为止。若是此时到达了原型链的顶部,也就是上例中的 Object.prototype
,仍然未发现须要查找的属性,那么 Javascript
就会返回 undefined
值。this
尽管原型对象的属性被 Javascript
用来构建原型链,咱们仍然能够值赋给它。可是原始值复制给 prototype
是无效的,如:prototype
function Foo() {} Foo.prototype = 1; // no effect
这里讲个本篇的题外话,介绍下什么是原始值:
在 Javascript
中,变量能够存放两种类型的值,分别是原始值和引用值。指针
1.原始值
(primitive value)
:
原始值是固定而简单的值,是存放在栈stack
中的简单数据段,也就是说,它们的值直接存储在变量访问的位置。
原始类型有如下五种型:Undefined, Null, Boolean, Number, String
。code
2.引用值
(reference value)
:
引用值则是比较大的对象,存放在堆heap
中的对象,也就是说,存储在变量处的值是一个指针pointer
,指向存储对象的内存处。全部引用类型都集成自Object
。
若是须要查找的属性位于原型链的上端,那么查找过程对于性能而言无疑会带来负面影响。当在性能要求必要严格的场景中这将是须要重点考虑得因素。此外,试图查找一个不存在属性时将会遍历整个原型链。
一样,当遍历一个对象的属性时,全部在原型链上的属性都将被访问。
理解原型式继承是写较为复杂的 Javascript
代码的前提,同时要注意代码中原型链的高度。当面临性能瓶颈时要学会将原型链拆分开来。此外,要将原型对象 prototype
和原型 __proto__
区分开来,这里主要讨论原型对象 prototype
就不阐述关于原型 __proto__
的问题了,若是有疑惑的话,能够阅读 @nightire 凡哥的博文《理解 JavaScript(四)》。
http://bonsaiden.github.io/JavaScript-Garden/#object.prototype