Javascript继承机制(call、apply、prototype)

Javascript的继承可以通过call、apply、prototype实现。

1、call:在子类中,用父类.call(this,arg0,arg1...)可以继承父类。注意call的位置,尽量在子类的第一行(js按顺序执行,放在后面可能对子类的其他属性、方法有影响。比如子类和父类有相同名字的方法,后面的覆盖前面的)。

[javascript]  view plain copy
  1. <html>  
  2. <head>  
  3. <title>call/apply/prototype test</title>  
  4. </head>  
  5. <script type="text/javascript">  
  6.     //person类  
  7.     function person(name, age) {  
  8.         this.name = name;  
  9.         this.age = age;  
  10.         this.say = function() {  
  11.             document.write("I am a person");  
  12.         }  
  13.         this.display = function() {  
  14.             document.write(this.name + "-" + this.age);  
  15.         }  
  16.     }  
  17.     //student类,继承自person  
  18.     function student(name, age, no) {  
  19.         person.call(this, name, age);//person中的this等于参数中的this,即student中的name和age  
  20.         this.no = no;  
  21.         this.display = function() {//覆盖了父类的方法  
  22.             document.write(this.name + "-" + this.age + "-" + this.no);  
  23.         }  
  24.     }  
  25.   
  26.     //创建person类  
  27.     var p = new person("captain", 21);  
  28.     p.display();//captain-21  
  29.     p.say();//I am a person  
  30.     //创建student类  
  31.     var s = new student("captain", 21, "06281097")  
  32.     s.display();//captain-21-06281097   
  33.     s.say();//I am a person 继承了父类的方法  
  34. <script>  
  35. <body>  
  36. </body>  
  37. </html>  

2、apply:在子类中,用父类.apply(this,args)可以继承父类(args为参数数组)。

[javascript]  view plain copy
  1. <html>  
  2. <head>  
  3. <title>call/apply/prototype test</title>  
  4. </head>  
  5. <script type="text/javascript">  
  6.     //person类  
  7.     function person(name, age) {  
  8.         this.name = name;  
  9.         this.age = age;  
  10.         this.say = function() {  
  11.             document.write("I am a person");  
  12.         }  
  13.         this.display = function() {  
  14.             document.write(this.name + "-" + this.age);  
  15.         }  
  16.     }  
  17.     //student类,继承自person  
  18.     function student(name, age, no) {  
  19.         person.apply(thisnew Array(name, age));//与call不同的是,apply传递的是数组  
  20.         this.no = no;  
  21.         this.display = function() {//覆盖了父类的方法  
  22.             document.write(this.name + "-" + this.age + "-" + this.no);  
  23.         }  
  24.     }  
  25.   
  26.     //创建person类  
  27.     var p = new person("captain", 21);  
  28.     p.display();//captain-21  
  29.     p.say();//I am a person  
  30.     //创建student类  
  31.     var s = new student("captain", 21, "06281097")  
  32.     s.display();//captain-21-06281097   
  33.     s.say();//I am a person 继承了父类的方法  
  34. <script>  
  35. <body>  
  36. </body>  
  37. </html>  

3、prototype:类.prototype可以为类的所有实例添加属性或方法

[javascript]  view plain copy
  1. <html>  
  2. <head>  
  3. <title>call/apply/prototype test</title>  
  4. </head>  
  5. <script type="text/javascript">  
  6.     //定义学生类(姓名、学好、年龄)  
  7.     function student(name, no, age) {  
  8.         this.name = name;  
  9.         this.no = no;  
  10.         this.age = age;  
  11.     }  
  12.     //学生实例  
  13.     var captain = new student("captain""06281097", 21);  
  14.     //添加学校属性  
  15.     student.prototype.school = null;  
  16.     //为captain学生的学校属性赋值  
  17.     captain.school = "BJTU";  
  18.     //显示captain的学校  
  19.     document.write(captain.school);  
  20. <script>  
  21. <body>  
  22. </body>  
  23. </html>  

可见,通过prototype为类添加属性是不方便的,因为构造函数已经固定,实例化时无法对新加入的属性进行初始化。比如上例中的school属性,在新建student对象时,无法通过new student(name,no,age,school)进行初始化,很不方便。所以一般都用prototype为类添加方法。

使用prototype进行继承时,还存在着一些问题,比如下例中的student.prototype=new person();这里无法加入参数,因为一旦加入参数则所有的student实例的name和age都是固定的值。这种情况下就需要用call和prototype进行联合。

[javascript]  view plain copy
  1. <script type="text/javascript">  
  2.     //person类  
  3.     function person(name, age) {  
  4.         this.name = name;  
  5.         this.age = age;  
  6.         this.say = function() {  
  7.             document.write("I am a person");  
  8.         }  
  9.         this.display = function() {  
  10.             document.write(this.name + "-" + this.age);  
  11.         }  
  12.     }  
  13.     //student类  
  14.     function student(name, age, no) {  
  15.         this.no = no;  
  16.         this.display = function() {//覆盖了父类的方法  
  17.             document.write(this.name + "-" + this.age + "-" + this.no);  
  18.         }  
  19.     }  
  20.     student.prototype = new person();//student继承person(无法写带参构造函数)  
  21.     //student.prototype = new person("name","age");//所有student实例的姓名都为name,年龄是age  
  22.   
  23.     var s = new student("captain", 21, "06281097");  
  24.     s.say();//I am a person  
  25.     s.display();//undefined-undefined-06281097   
  26.     //student的name、age没有从参数中获得(两个属性要在person的构造行数中获得,但是prototype的构造函数无参)  
  27. <script>  

4、call和prototype联合:解决了使用prototype不能使用带参构造函数的问题。在父类中,只定义属性字段,通过prototype为类添加方法。在子类中,通过call来调用父类带参构造函数,通过 子类.prototype=new 父类() 来继承父类的方法。

[javascript]  view plain copy
  1. <script type="text/javascript">  
  2.     //person类  
  3.     function person(name, age) {  
  4.         this.name = name;  
  5.         this.age = age;  
  6.     }  
  7.     person.prototype.say = function() {//为person类添加say方法  
  8.         document.write("I am a person");  
  9.     };  
  10.     person.prototype.display = function() {//为person类添加display方法  
  11.         document.write(this.name + "-" + this.age);  
  12.     };  
  13.       
  14.     //student类  
  15.     function student(name, age, no) {  
  16.         person.call(this,name,age);//可以获得父类构造方法(this.name=name;this.age=age;)  
  17.         this.no = no;  
  18.     }  
  19.     student.prototype = new person();//没有此句,student类无法获得person的say/display方法  
  20.     student.prototype.display = function() {//为student类添加display方法,并覆盖了父类的方法  
  21.         document.write(this.name + "-" + this.age + "-" + this.no);  
  22.     };  
  23.   
  24.     var s = new student("captain", 21, "06281097");  
  25.     s.say();//I am a person  
  26.     s.display();//captain-21-06281097   
  27. <script>  

5、继承之后的类型:用call继承,类型并没有发生变化;用prototype继承,类型也继承父类。详见下例

[javascript]  view plain copy
  1. <script type="text/javascript">  
  2.     //person类  
  3.     function person(name, age) {  
  4.         this.name = name;  
  5.         this.age = age;  
  6.     }  
  7.   
  8.     //student类,继承自person(call)  
  9.     function student(name, age, no) {  
  10.         person.call(this, name, age);  
  11.         this.no = no;  
  12.     }  
  13.   
  14.     //programer类,继承自person(prototype)  
  15.     function programer(name, age, sex) {  
  16.         this.sex = sex;  
  17.     }  
  18.     programer.prototype = new person();  
  19.   
  20.     //man类,继承自person(prototype)  
  21.     function man(name, age, height) {  
  22.         person.call(this, name, age);  
  23.         this.height = height;  
  24.         this  
  25.     }  
  26.     man.prototype.say = function() {  
  27.         alert(this.name);  
  28.     };  
  29.   
  30.       
  31.     //创建person实例  
  32.     var p = new person("captain", 21);  
  33.     //创建student实例  
  34.     var s = new student("captain", 21, "06281097");  
  35.     //创建programer实例  
  36.     var g = new programer("captain", 21, "男");  
  37.     //创建man实例  
  38.     var m = new man("captain", 21, 176);  
  39.   
  40.     //判断类型(typeof返回全是object,所以用instanceof)  
  41.     alert(s instanceof person);//false 使用call并不是完全的继承  
  42.     alert(s instanceof student);//true  
  43.     alert(g instanceof person);//true   
  44.     alert(g instanceof programer);//true  
  45.     alert(m instanceof person);//false   
  46.     //只有使用prototype添加父类的构造函数,才能在意义上完全继承person  
  47.     alert(m instanceof man);//true  
  48. <script>  

你可能感兴趣的:(Javascript继承机制(call、apply、prototype))