您的位置:首页 > Web前端 > JavaScript

深入理解js面向对象中的prototype

2017-05-26 14:09 671 查看
一、基本使用方法
 
   prototype属性可算是JavaScript与其他面向对象语言的一大不同之处。prototype就是“一个给类的对象添加方法的方法”,使用prototype属性,可以给类动态地添加方法,以便在JavaScript中实现“继承”的效果。
 
   具体来说,prototype 是在 IE 4 及其以后版本引入的一个针对于某一类的对象的方法,当你用prototype编写一个类后,如果new一个新的对象,浏览器会自动把prototype中的内容替你附加在对象上。这样,通过利用prototype就可以在JavaScript中实现成员函数的定义,甚至是“继承”的效果。
 
    对于javascript本身而言是基于对象的,任何元素都可以看成对象。然而类型和对象是不同的,而我们所讲的prototype属性即是基于类型的一种属性。对于prototype的基本使用就如对象的创建及属性赋值一样的简单。直接通过赋值操作即可完成属性的创建。如:
 
var objectRef = new Object();  // 创建一个最基本的js对象
 
一个名为property的属性即可如下进行创建:
objectRef.property = 6;  
objectRef["property"] = 6;  
 
对于prototype的赋值也是类似,如下所示:
//首先创建一个基本的AClass类型  
  
var AClass = function() {  
  
   this.property = 5;   
  
};  
  
//可以通过prototype属性来为该类型新增属性或方法  
  
AClass.prototype.Method = function() {  
  
    alert(5);  
  
}  
所有对象本身都可以有prototype属性,它本身也是对象。如此循环下去就形成一个prototype链,这个链当遇到链中的prototype为null时即中止。(Object的默认prototype是null)。
 
    如上代码var objectRef = new Object(),这个对象的prototyp是null, 所以objectRef的prototype链只包含一个对象Object.prototype。
 
    分析如下的代码结构,可以看出类型MyClass2本身并没有定义testNumber,但通过prototype属性将MyClass1的所有定义都继承下来了,而且还继承了Object中的toString方法。因此该prototype的链包含3个。
 
<script>  
    var MyClass1 =function(formalParameter) {  
  
        this.testNumber =formalParameter;  
  
    };  
  
   
  
    var MyClass2 = function(formalParameter){  
  
        this.testString  = formalParameter;  
  
};  
 
    MyClass2.prototype = new  MyClass1(9);  
 
    var myObject2 = new  MyClass2("Hello World!");  
  
    alert(myObject2.testString);//Hello World!  
  
    alert(myObject2.testNumber); //9  
  
    alert(myObject2.toString); //function toString() {}  
  
</script>  
 
二、JS中的面向对象
 
JS中最简单的对象即为内嵌型的Object数据类型,如下所示,我们可以新建一个新的对象,并为其添加几个属性。
 
var obj = new Object();  
obj.x = 1;  
obj.y = 2;     
可以用如下的图示来表示该对象。该对象中有两上属性,同时还包含一个隐含的prototype对象。

Obj

x

1

y

2

Object.prototype

constructor

Object

当然我们也可以构造如下带有构造函数的类,并生成其对象。

 
 
 
 
 
var AClass = function() {  
  
    this.x = 1;  
  
    this.y = 2;  
  
}  
var obj = new AClass();  
此时,该对象的内部结构即如下图所示。其中包含了一个构造函数。

obj

x

1

y

2

AClass.prototype

constructor

AClass

Object.prototype

(constructor)

Object

在js中,每个对象都可以继承自另外一个其它的对象,我们可以称之为引用原型。当我们访问一个属性时,如果能通过对象本身直接找到,则返回,否则它会向引用原型中追溯,直到根部prototype(即object)。如下所示:

Object.prototype.inObj = 1;  
  
var A = function() {  
  
    this.inA = 2;  
  
}  
  
A.prototype.inAProto = 3;  
  
var B = function() {  
  
    this.inB = 4;  
  
}  
  
B.prototype = new A();  
  
B.prototype.inBProto = 5;  
  
var x = new B();  
  
alert(x.inObj + “,” + x.inA + “,” + x.inAProto + “,” + x.inB + “,” +x.inBProto); //1, 2, 3, 4, 5  
对于上述的代码,创建一个对象x,它所生成的prototype链结构如下:

 

对应生成的对象x的内部结构图如下所示:

x

inB

4

B.prototype

constructor

B

inA

2

inBProto

5

A.prototype

(constructor)

A

inAProto

3

Object.prototype

(constructor)

Object

inObj

1

 
三、prototype的继承使用
 
1、将ClassA的一个实例赋值给ClassB,则 ClassB就继承了ClassA的所有属性。
 
<script>  
  
    var ClassA = function() {  
 
        this.a = "a";  
  
    };  
  
    var ClassB = function() {  
  
    this.b= "b";  
  
    };  
  
   
  
    ClassB.prototype = new ClassA();  
  
    var objB = new ClassB();  
  
    alert(objB.a); // a  
  
    alert(objB.b); // b  
  
</script>  
 
 
 
 
从上述的变量输出结果,可以看出本身ClassB是没有属性a的,但在创建的对象中调用objB.a时却输出了a,说明在执行ClassB.prototype= new ClassA();后,ClassB继承了ClassA的所有属性。
 
2、js的原型继承是引用原型,而不是复制原型。当修改原型时会导致所有的实例变化。
 
<script>  
  
     var ClassA = function() {  
  
     this.a = "a";  
  
     };  
  
  
     var ClassB = function() {  
  
         this.b = "b";  
  
     };  
  
     ClassB.prototype = new ClassA();  
  
     var objB = new ClassB();  
  
     alert(objB.a); // a  
  
     ClassB.prototype.a ="changed";  
  
     alert(objB.a); //changed  
  
</script>  
 
由上述代码可以看出,即使对象创建于原型修改之前,但仍然会生效。这就印证了js是引用原型。即使是在对象创建之后修改,仍然会对之前生成的对象生效。
 
3、每个子类对象都执行同一个原型的引用,所以子类对象中的原型成员实际是同一个
 
 
 
 
 
 
 
<script>  
  
    var ClassA = function() {  
  
         this.a = "a";  
  
         this.Method = function() {  
  
        alert("ClassA");  
  
         }  
  
    };  
  
    var ClassB = function() {  
  
         this.b = "b";  
  
    };  
  
    ClassB.prototype = new ClassA();  
  
    var objB1 = new ClassB();  
  
    var objB2 = new ClassB();  
  
    alert(objB1.a == objB2.a); //true  
  
    alert(objB1.b == objB2.b); //true  
  
    alert(objB1.Method ==objB2.Method);  
  
</script>
 
4、子类对象的写操作只访问子类对象的成员,相互之间不产生影响。写一定是写子类,读则要看是否子类中有,若有则读子类,若无则读原型。

1. <script>  

2.   

3.     var ClassA = function() {  

4.   

5.      this.a = "a";  

6.   

7.     };  

8.   

9.     var ClassB = function() {  

10.   

11.          this.b = "b";  

12.   

13.     };  

14.   

15.     ClassB.prototype = new ClassA();  

16.   

17.     var objB1 = new ClassB();  

18.   

19.     var objB2 = new ClassB();  

20.   

21.     objB1.a = "change";  

22.   

23.     alert(objB1.a);  // change  

24.   

25.     alert(objB2.a);  // a  

26.   

27. </script>  

由上述代码分析,其中由于进行了objB1.a进行了重新改变,所以其值在接下来进行了改变,但它不会影响到objB2对象。但若是原型发生了变化,则如2所示,它下面的所有实例均会发生变化。

 

5、构造子类时,原型的构造函数不会被执行

[javascript] view
plain copy print?
1. <script>  

2.   

3.     var ClassA = function() {  

4.   

5.         alert("ClassA");  

6.   

7.         this.a = "a";  

8.   

9.     };  

10.   

11.     var ClassB = function() {  

12.   

13.         alert("ClassB");  

14.   

15.         this.b = "b";  

16.   

17.     };  

18.   

19.     ClassB.prototype = new ClassA();// ClassA  

20.   

21.     var objB1 = new ClassB();  // ClassB  

22.   

23.     var objB2 = new ClassB();  // ClassB  

24.   

25. </script>  

由此可以看出,在构造子类时并没有象Java中那样需要调用父类的构造函数。

6、在子类对象中访问原型的成员对象,会影响到其它对象

1. <script>  

2.   

3.     var ClassA = function() {  

4.   

5.         this.a = [];  

6.   

7.     };  

8.   

9.     var ClassB = function() {  

10.   

11.         this.b = "b";  

12.   

13.     };  

14.   

15.     ClassB.prototype = new ClassA();  

16.   

17.     var objB1 = new ClassB();  

18.   

19.     var objB2 = new ClassB();  

20.   

21.     objB1.a.push(1,2,3);  

22.   

23.     alert(objB2.a); // 1,2,3  

24.   

25. </script>  

由此可以看出,在子类对象中访问原型的成员对象后,由于采用的是引用原型方式,其实它和ClassB.a.push实现的是同样的功能。所以其它的子类也会跟着变化。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  面向对象 javascript