【JavaScript学习笔记】理解prototype-原型

写这个笔记是由于最近在看《JavaScript高级程序设计(第三版)》,原书写得很是好,讲解也很是细致,甚至能够做为一本手册(我少有喜欢一本手册式的教材,不过这本绝对是个例外!)。在这本书里学到了很多东西,不动笔墨不读书,为了本身仍是决定总结一些笔记出来,笔记里的东西基本都出自书中,不过以本身的方式说出来而已。再次热烈推荐原书,真的好赞!css

1. 原型(prototype) 是什么呢html

若是解释的广义一点,应该说原型是某一类对象的共同的性质或者特征。具体说来,在JavaScript中里原型是定义在 function 和 对象里的一项属性。更明确一点说,好比每当建立了一个 function, 这个 function 内部就默认有一个 prototype 的属性。浏览器

2. 原型自己是什么类型呢?函数

原型自己实际上是一个对象,是object 。this

3. function 和 对象里的原型有什么不同的吗?spa

function 的原型是能够显式地经过 prototype 访问的,你能够动态的去添加属性,方法,你甚至能够本身建立一个 object, 将它赋值给一个 function 的 prototype; .net

而 object 的原型是没法经过标准方式显式地获得的,说得更具体一点,每当建立了一个object,不管是经过何种方式建立,这个 object 内部都会包含一个指针,这是一个内部属性,ECMA-262第5版中管这个指针叫  [ [ Prototype ] ]  , 虽然没有一个标准的方式去访问它,可是在 Firefox, Chrome, Safari 里每一个对象上都支持一个__proto__  属性, 经过这个属性能够去访问原型,而在其余浏览器的实现中,这个属性则彻底是不可见的。prototype

4. 经过 function 获得的原型和经过对象的到的原型有什么联系吗?设计

终于到重点了,(严格的说,把这部份内容描述为两种原型的联系实际上是不正确的,可是当了解完这部份内容后,怎么定义其实并不重要啦,眨眼),咱们来看示例,首先定义一个函数(构造函数),指针

 1: function Person(name, age) {
 2:     this.name = name;
 3:     this.age = age;
 4: }

这时咱们就有了一个 function,并且这个 function 会有一个 prototype 的属性, 经过这个属性能够访问该函数的原型,具体见下图,

未命名

从图中能够看出,其实不只仅是能够经过 Person.prototype 访问原型,原型中也有一个 constructor 的属性,Person.prototype.constructor 就指向 Person 函数自身。

接下来,咱们再建立两个 Person 的实例,

 1: var p1 = new Person("Bob", 20);
 2: var p2 = new Person("Peter", 22);

这时候发生了什么呢,来看看下图,

未命名2

当建立了实例 p1 和 p2 以后,p1, p2 内都存在内部属性 [ [ Prototype ] ], 而这个属性,其实就指向构造函数 Person 的原型,有趣的是 p1 和 p2 和构造函数 Person 自己没有直接的关系, 它们的联系就是它们都指向了同一个原型!

5. 我在构造函数的原型中添加了方法,为何经过构造函数建立的实例也能够直接访问这个方法呢?

也许写一段code能帮助理解上面的问题,

 1: Person.prototype.sayHi = function () {
 2:     alert("Hi");
 3: }
 4:  
 5: var p1 = new Person();
 6: p1.sayHi(); // why this works?

其实,每当读取对象的某个属性时,都会执行一次搜索,目标是具备给定名字的属性,搜索首先从对象实例自己开始,若是在实例中找到了具备给定名字的属性,则返回该属性的值,若是没有找到,则继续搜索该实例的原型,在原型对象中查找具备给定名字的属性

6. 若是我没有采用构造函数的方式建立一个对象实例,那该实例的 [[ Prototype ]] 会指向什么呢?

假若采用通常的方式建立一个对象实例,好比

 1: var obj1 = {};
 2: var obj2 = new Object();

想必你已经猜到,此时 [ [ Prototype ] ] 会指向 Object 的 prototype。

7. 当建立了一个对象实例的时候,它的默认的toString等方法藏在哪里?

没错,就藏在原型里,但不妨讲得更具体一点,假设以前的 script 已经运行过,如今,咱们有了一个 Person 函数,咱们有了 Person 的实例 p1,当咱们直接调用 p1.toString() 会怎样呢,根据问题5,咱们知道当在实例自己中搜索不到 toString 时,会转而搜索实例的 [ [ Prototype ] ] 指向的 Person.prototype, 可是 Person.prototype 里其实仍然没有定义 toString ! 而后,咱们意识到其实 Person.prototype 也是一个Object!那么继续,再次根据问题5,Person.prototype 的[[Prototype]] 指向哪里呢? 没错就是 Object 的 prototype, toString 就在这里。

其实咱们能够用console.dir(Person.prototype.__proto__)查看,你会发现你看到的就是Object Prototype,这里面定义了 valueOf, toString 等等方法。

看到这里,咱们已经能够隐约感到JavaScript中面向对象的继承机制了…… 原型的运用对继承的实现相当重要!

对原型的总结就到这里,这里所列的仅仅是一部分,但我认为这是理解原型中比较重要的一部分,还有一些有关原型的方法,就再也不赘述了。

相关文章
相关标签/搜索