理解Javascript_05_原型继承原理
2011-06-15 18:17
671 查看
对于面向对象的基础语法在此我就不重复了,对面向对象不熟悉的朋友可以参看《使用面向对象的技术创建高级 Web 应用程序》一文。
prototype与[[prototype]]
在有面象对象基础的前提下,来看一段代码:
view source
print?
其对应的简易内存分配结构图:
现在让我们来解释一下这张内存图的来龙去脉:
首先明确一点[[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]]、原型链以及属性访问的相关要点:
view source
print?
根据上面的代码,你能画出相应的内存图吗?好,让我们来看一下:
注:prototype的根为Object.prototype,对象Object.prototype的内部[[prototype]]属性为null。其实,这里还有很多东西可以讲,但在其原理都在这张图上了,可试着调整一下代码的次序,如将Human.prototype.id ="Human";放在Human.prototype =new Animal();的前面,看一下运行结果,解释一下为什么之类的,你可以学到很多。
我发现,通过内存来展现程序内部运行细节真的是太完美了!
prototype与[[prototype]]
在有面象对象基础的前提下,来看一段代码:
view source
print?
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 | var dog = new Animal( "旺才" ); |
13 | alert(dog.name); //旺才 |
14 | alert(dog.id); //Animal |
15 | 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]]、原型链以及属性访问的相关要点:
view source
print?
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 | function Human(name,age){ |
13 | Animal.call( this ,name); |
14 | this .age = age; |
15 | } |
16 | Human.prototype = new Animal(); |
17 | Human.prototype.id = "Human" ; |
18 | Human.prototype.say = function (){ |
19 | alert( "hello everyone,My name is " + this .name + ",I'm " + this .age+ " and I'm a " + this .id); |
20 | } |
21 | //Human相关调用 |
22 | var jxl = new Human( '笨蛋' ,25); |
23 | alert(jxl.name); //笨蛋 |
24 | alert(jxl.id); //Human |
25 | jxl.say(); //hello everyone,My name is 笨蛋,I'm 25 and I'm a Human |
26 | alert(Animal.prototype.isPrototypeOf(jxl)); //true |
27 | alert(Object.prototype.isPrototypeOf(jxl)); //true |
注:prototype的根为Object.prototype,对象Object.prototype的内部[[prototype]]属性为null。其实,这里还有很多东西可以讲,但在其原理都在这张图上了,可试着调整一下代码的次序,如将Human.prototype.id ="Human";放在Human.prototype =new Animal();的前面,看一下运行结果,解释一下为什么之类的,你可以学到很多。
我发现,通过内存来展现程序内部运行细节真的是太完美了!
相关文章推荐
- 理解Javascript_05_原型继承原理
- 理解Javascript_05_原型继承原理
- 理解Javascript_05_原型继承原理
- 理解Javascript_05_原型继承原理
- 理解Javascript_05_原型继承原理javascript
- 理解Javascript_05_原型继承原理 ,转载文章
- javascript中继承(一)-----原型链继承的个人理解
- 深入理解javascript原型和闭包(6)——继承
- 深入理解javascript原型和闭包(6)——继承
- JavaScript原型彻底理解2---继承中的原型链
- javascript中继承(一)-----原型链继承的个人理解
- 深入理解Javascript中的原型、原型链、继承
- 深入理解javascript原型和闭包(6)——继承
- 深入理解JavaScript中的继承:原型链篇
- 深入浅出理解Javascript原型概念以及继承机制(转)
- 【web前端-理解js原型】理解Javascript中的原型对象、原型链和继承
- 彻底理解Javascript原型继承
- 深入理解javascript原型和闭包(6)——继承
- javascript中原型继承(prototype inherit)的理解
- JavaScript-原型继承工作原理