javascript原型链继承

一、关于javascript原型的基本概念:

prototype属性:每个函数都一个prototype属性,这个属性指向函数的原型对象。原型对象主要用于共享实例中所包含的的属性和方法。

constructor属性:每个原型对象都有一个constructor属性,这个constructor属性包含一个指向prototype属性所在函数的指针。 例如 Foo.prototype.constructor指向Foo函数。这个属性是只读的。

__proto__属性(ES6通过对__proto__属性进行标准化):创建一个构造函数的实例后,这个实例包含一个指针,指向这个构造函数的原型对象,这个指针叫做[[Prototype]],在chrome、Safari、Firefox下可通过对象的__proto__属性访问。__proto__属性是实例才拥有的,在javascript中函数也是对象,它是Function类型的实例, 所以函数也有__proto__属性。

我们来看这样一个关系图:

(图片来自:http://www.mollypages.org/misc/js.mp)

通过这个关系图,我们可以得到以下信息:

  • 实例的__proto__属性始终指向它构造函数的原型对象:
1 function Foo(){};
2 var foo=new Foo();
3 console.log(foo.__proto__===Foo.prototype); //true
4 console.log(Foo.__proto__===Foo.constructor.prototype);//ture
  • 所有对象最终都会指向Object对象:
1 function Foo(){};
2 var foo=new Foo();
3 console.log(foo.__proto__); //输出Foo{},表示指向Foo构造函数的原型
4 console.log(foo.__proto__.__proto__); //输出Object{},表示指向Object构造函数的原型
5 console.log(foo.__proto__.__proto__.__proto__); //null
  • 用户自定义函数的__proto__属性指向Function.prototype,所以它们都是Function构造函数的实例。

二、开始说原型链继承:

  现在,有了前面基本概念的了解,我再说关于原型链的继承,首先来看以下代码:

 1 function Foo(name){
 2     this.name=name;
 3 }
 4 Foo.prototype.myName=function(){
 5         console.log("my name is "+this.name);
 6 }
 7
 8 function Bar(name){
 9      this.name=name;
10 }
11 Bar.prototype=new Foo(); //Bar的原型指向Foo的实例
12 var bar=new Bar("Dog");
13 bar.myName();//输出:”my name is Dog“

  以上代码实现了Bar构造函数继承了Foo构造函数的myName()方法。继承是通过原型链的查找来实现的,原型链的查找规则是:当实例调用一个属性(或方法)时,首先会在这个实例中查找该属性(或方法),在没有找到的情况下,会继续在这个实例的原型上查找,如果依旧找不到这个属性(或方法),搜索过程会沿着原型链向上查找,直到原型链的末端,整个查找过程才会停止。上面例子的原型链关系如图:

例子中当实例bar调用myName()方法时,会首先在bar这个实例中查找有没有myName()这个方法,如果没有找到,则会在Bar.prototype上查找,在Bar.prototype上没有找到的情况下,继续在Foo.prototype上查找,结果在Foo.prototype上找到了该方法。

 为什通过 “Bar.prototype=new Foo()” 能够实现这样有继承关系的原型链呢?我们可以通过以下代码来验证:

 1 function Foo(name){
 2     this.name=name;
 3 }
 4 Foo.prototype.myName=function(){
 5         console.log("my name is "+this.name);
 6 }
 7
 8 function Bar(name){
 9      this.name=name;
10 }
11
12 var foo=new Foo();
13 Bar.prototype=foo;
14 var bar=new Bar();
15 bar.__proto__===Bar.prototype;  //返回true
16 bar.__proto__===foo; //返回true
17 bar.__proto__.__proto__===foo.__proto__; //返回true
18 foo.__proto__===Foo.prototype; //返回true,证明了Bar 继承了Foo

  或许你会问通过“Bar.prototype=new Foo()”能够实现继承,为什么不是“Bar.prototype=Foo.prototype”呢?好的,下面先看这段简单的代码:

1 a={a:1,b:2};
2 b=a;
3 b.c=3;
4 console.log(a.c); //3 ,a和b是引用类型

  看完这段代码,我们想象一下,Bar.prototype  和Foo.prototype也是Object类型的,所以它们之间相互赋值,将指向相同数据地址,若修改Bar原型上的属性,Foo原型上的同名属性也会被修改,来看看下面的示例:

 1 function Foo(){}
 2 Foo.prototype.name="Dog";
 3 Foo.prototype.sayName=function(){
 4  console.log("My name is " +this.name);
 5 }
 6 var foo=new Foo();
 7 foo.sayName();//"My name is Dog"
 8 function Bar(){}
 9
10 Bar.prototype=Foo.prototype;
11 Bar.prototype.name="Cat";
12 var bar=new Bar();
13 bar.sayName();//"My name is Cat",也能Foo原型上的方法14 foo.sayName();//"My name is Cat",Foo原型上的name属性已经被修改

  通过上面的示例我们可以看到,当“Bar.prototype=Foo.prototype”时,如果给Bar.prototype上添加一个name属性,Foo.prototype上name属性也将随之被修改,我们知道继承的目的就是子函数(子类)复用、重写、扩展父函数(父类)的方法,但继承决不允许改变父函数(父类)的方法和属性 ,所以Bar.prototype=Foo.prototype是不能实现继承的。
  那么让“Bar.prototype=Foo”能不能实现继承呢?我们来用代码验证一下:

1 function Foo(){}
2 function Bar(){}
3 Bar.prototype=Foo;
4 var bar=new Bar();
5 bar.__proto__===Bar.prototype; //true
6 bar.__proto__===Foo; //true
7 Foo.__proto__===Function.prototype; //ture
8 Function.prototype.__proto__===Object.prototype; //ture
9 Object.prototype.__proto__===null; //ture

通过bar.__proto__向上查找不到Foo.prototype,所以Bar构造函数是不能继承Foo构造函数的。

参考资料:《javascript高级程序设计》

《JavaScript 继承代码中,B.prototype = new A(); 的含义是什么?》

=============================================================================================

最后:欢迎给我留言,帮我指出我理解错误的地方或指出你不理解的地方。

本文地址:http://www.cnblogs.com/liubaozhe/p/4618989.html

时间: 2024-11-08 22:06:47

javascript原型链继承的相关文章

老生常谈之JavaScript原型链继承

介绍 本文总结了ES3,ES5,ES7和NS(NonStandard)四种原型链继承的实现方法. 前言 ECMAScript 6 class将给开发者带来JavaScript OOP的规范实现,但这种方式的直接应用和普及至少得等到IE11被淘汰掉,而到那时,说不定我们已转向边沿领域了. 随着Web的快速发展,新的方法可能会随时取代旧的方法,而我们在lifetime中用过的方法,代表着一代人的记忆,又怎能忘怀? 分享 另附上BDD测试 这其中: 较新的JavaScript运行环境能兼容旧的继承方法

8条规则图解JavaScript原型链继承原理

原形链是JS难点之一,而且很多书都喜欢用一大堆的文字解释给你听什么什么是原型链,就算有图配上讲解,有的图也是点到为止,很难让人不产生疑惑. 我们先来看一段程序,友情提示sublimeText看更爽: <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edg

【笔记】javascript原型链继承实例

function Shape(){ this.name = 'shape'; this.toString = function(){ return this.name; } } function TwoDShape(){ this.name = '2D shape'; } function Triangle(side,height){ this.name = 'Triangle'; this.side = side; this.height = height; this.getArea = fu

Javascript的原型、原型链、原型链继承

原型 在javascript中,原型分有两种:显示原型(prototype)和隐式原型(__proto__). __proto__(隐式原型) JavaScript中任意对象都有一个内置属性[[prototype]],在ES5之前没有标准的方法访问这个内置属性,但是大多数浏览器都支持通过__proto__来访问.ES5中有了对于这个内置属性标准的Get方法Object.getPrototypeOf(). prototype(显式原型) 这是函数对象特有的属性.这个属性是一个指针,指向一个对象,这

Javascript 组合继承 原型链继承 寄生继承

Javascript继承通常有三种方式. 第一种:组合式继承: function SuperType(name) { this.name = name; this.colors = ["red", "blue", "green"]; } SuperType.prototype.sayName = function() { console.log(this.name); }; function SubType(name, age) { //通过ca

一步步学习javascript基础篇(5):面向对象设计之对象继承(原型链继承)

上一篇介绍了对象创建的几种基本方式,今天我们看分析下对象的继承. 一.原型链继承 1.通过设置prototype指向“父类”的实例来实现继承. function Obj1() { this.name1 = "张三"; } function Obj2() { } Obj2.prototype = new Obj1(); var t2 = new Obj2(); alert(t2.name1); 这里有个明显的缺点就是:(如果父类的属性是引用类型,那么我们在对象实例修改属性的时候会把原型中

明白JavaScript原型链和JavaScrip继承

原型链是JavaScript的基础性内容之一.其本质是JavaScript内部的设计逻辑. 首先看一组代码: 1 <script type="text/javascript"> 2 function parent(){ 3 this.name="cehis"; 4 } 5 6 function son(){ 7 this.age=11; 8 } 9 10 function sub(){ 11 this.sex="nan"; 12 }

javascript 的 继承(一) 之 原型链继承

继承 继承是 OO语言中的一个最为人津津乐道的概念.许多 OO语言都支持两种继承方式:接口继承和实现继承. 接口继承只继承方法签名,而实现继承则继承实际的方法. 如前所述,由于函数没有签名,在 ECMAScript中无法实现接口继承.ECMAScript只支持实现继承,而且其实现继承主要是依靠原型链来实现的. 1.原型链 ECMAScript中描述了原型链的概念,并将原型链作为实现继承的主要方法. 其基本思想是利用原型让一个引用类型继承另一个引用类型的属性和方法. 简单回顾一下构造函数.原型和实

JavaScript继承-原型链继承

//原型链继承 function SuperType(){ this.name = 'super'; this.girlFriends = ["xiaoli","xiaowang"]; } SuperType.prototype.sayName = function(){ console.log(this.name); } function SubType(){ this.age = 20; } //创建SuperType的实例赋给SubType的原型 //实现继承