原型继承原理

简介:

prototype与[[prototype]]

在有面象对象基础的前提下,来看一段代码:

01 //Animal构造函数
02 function Animal(name){
03     this.name = name;
04 }
05 //Animal原型对象
06 Animal.prototype = {
07     id:"Animal",
08     sleep:function(){
09         alert("sleep");
10     }
11 }
12  
13 var dog = new Animal("旺才");
14 alert(dog.name);//旺才
15 alert(dog.id);//Animal
16 dog.sleep()//sleep

其对应的简易内存分配结构图:

 

现在让我们来解释一下这张内存图的来龙去脉:

首先明确一点[[prototype]]与prototype并不是同一个东西。

  那先来看prototype,每一个函数对象都有一个显示的prototype属性,它代表了对象的原型,更明确的说是代表了由函数对象(构造函数)所创建出来的对象的原型。结合本例,Animal.prototype就是dog的原型,dog所引用的那个对象将从Animal.prototype所引用的对象那继承属性与方法。

  每个对象都有一个名为[[Prototype]]的内部属性,指向于它所对应的原型对象。在本例中dog的[[prototype]]指向Animal.prototype,大家都知道,Animal.prototype也是一个对象,即然是一个对象,那它必然也有[[prototype]]属性指向于它所对应的原型对象,由此便构成了一种链表的结构,这就是原型链的概念。额外要说的是:不同的JS引擎实现者可以将内部[[Prototype]]属性命名为任何名字,并且设置它的可见性,前且只在JS引擎内部使用。虽然无法在JS代码中访问到内部[[Prototype]](FireFox中可以,名字为__proto__因为Mozilla将它公开了),但可以使用对象的 isPrototypeOf()方法进行测试,注意这个方法会在整个Prototype链上进行判断。

注:关于函数对象的具体内容,将在后继的博文中讲解。

 

属性访问原则

使用obj.propName访问一个对象的属性时,按照下面的步骤进行处理(假设obj的内部[[Prototype]]属性名为__proto__):
1. 如果obj存在propName属性,返回属性的值,否则
2. 如果obj.__proto__为null,返回undefined,否则
3. 返回obj.__proto__.propName
调用对象的方法跟访问属性搜索过程一样,因为方法的函数对象就是对象的一个属性值。
提示: 上面步骤中隐含了一个递归过程,步骤3中obj.__proto__是另外一个对象,同样将采用1, 2, 3这样的步骤来搜索propName属性。

这就是基于Prototype的继承和共享。其中object1的方法fn2来自object2,概念上即object2重写了object3的方法fn2。
JavaScript对象应当都通过prototype链关联起来,最顶层是Object,即对象都派生自Object类型。

结合是上面的理论,让我们再来看一个更加复杂的示例,他明确的解释了prototype、[[prototype]]、原型链以及属性访问的相关要点:

01 //Animal构造函数
02 function Animal(name){
03     this.name = name;
04 }
05 //Animal原型对象
06 Animal.prototype = {
07     id:"Animal",
08     sleep:function(){
09         alert("sleep");
10     }
11 }
12  
13 function Human(name,age){
14     Animal.call(this,name);
15     this.age = age;
16 }
17  
18 Human.prototype = new Animal();
19 Human.prototype.id = "Human";
20  
21 Human.prototype.say = function(){
22     alert("hello everyone,My name is "+this.name +",I'm "+this.age+" and I'm a "+this.id);
23 }
24  
25 //Human相关调用
26 var jxl = new Human('笨蛋',25);
27 alert(jxl.name);//笨蛋
28 alert(jxl.id);//Human
29 jxl.say();//hello everyone,My name is 笨蛋,I'm 25 and I'm a Human
30  
31 alert(Animal.prototype.isPrototypeOf(jxl));//true
32 alert(Object.prototype.isPrototypeOf(jxl));//true

根据上面的代码,你能画出相应的内存图吗?好,让我们来看一下:

注:prototype的根为Object.prototype,对象Object.prototype的内部[[prototype]]属性为null.

其实,这里还有很多东西可以讲,但在其原理都在这张图上了,可试着调整一下代码的次序,如将Human.prototype.id = "Human";放在Human.prototype = new Animal();的前面,看一下运行结果,解释一下为什么之类的,你可以学到很多。

 

本文转自艾伦 Aaron博客园博客,原文链接:http://www.cnblogs.com/aaronjs/archive/2011/09/06/2168336.html,如需转载请自行联系原作者

相关文章
|
6月前
|
JavaScript 前端开发
js开发:请解释原型继承和类继承的区别。
JavaScript中的原型继承和类继承用于共享对象属性和方法。原型继承通过原型链实现共享,节省内存,但不支持私有属性。
51 0
|
6月前
|
前端开发 JavaScript
【面试题】原型与原型链 进一步理解~
【面试题】原型与原型链 进一步理解~
|
6月前
|
JavaScript 前端开发
深入探讨JavaScript中的原型链与继承机制
JavaScript作为一种灵活而强大的编程语言,其独特的原型链与继承机制是其核心特性之一。本文将深入探讨JavaScript中的原型链与继承机制,从基础概念到实际应用,帮助读者更好地理解和利用JavaScript的继承特性。
|
6月前
|
设计模式 前端开发 JavaScript
【面试题】 对象、原型、原型链与继承?这次我懂了!
【面试题】 对象、原型、原型链与继承?这次我懂了!
|
6月前
|
JavaScript 前端开发 Java
JavaScript难点:原型、原型链、继承、new、prototype和constructor
JavaScript 不像 Java、C++ 这种纯面向对象的语言,可以通过类实现继承,JavaScript中的继承是通过原型实现的,即使 ES6 中新增的 class 类也只是原型的语法糖而已
76 4
|
6月前
|
设计模式 前端开发 JavaScript
【面试题】对象、原型、原型链与继承 ,你了解多少?
【面试题】对象、原型、原型链与继承 ,你了解多少?
|
6月前
|
JavaScript 前端开发 Java
【面试常见】JS继承与原型、原型链
【面试常见】JS继承与原型、原型链
|
JavaScript 前端开发
如何理解原型及原型链?js的继承方式
如何理解原型及原型链?js的继承方式
60 0
一文搞懂原型和原型链
一文搞懂原型和原型链
121 0
一文搞懂原型和原型链
|
前端开发
前端学习案例1-原型&原型链&构造函数
前端学习案例1-原型&原型链&构造函数
43 0
前端学习案例1-原型&原型链&构造函数