zoukankan      html  css  js  c++  java
  • js怎么实现继承?

     

    3. js怎么实现继承?

      1. 使用原型prototype

      这个问题其实之前总结过了……但是面试时候有点忘……主要思想是记得的,但是不会写,还是基础太不牢靠,写的太少了。一开始因为不知道怎么能继承父类的方法属性,同时又不直接使用其原型,所以先写了一种,子类直接调用父类的原型。但是其中有些过程和方法肯定是写错了的……下面是正确的写法:

      

     1     var Parent = function(name){
     2         this.name = name || "parent";
     3     }
     4     Parent.prototype.getName = function(){
     5         return this.name;
     6     }
     7 
     8     var Child = function(name){
     9         Parent.apply(this,arguments);       //通过apply调用父类的构造函数来进行相同的初始化工作
    10     }
    11     Child.prototype = Parent.prototype;
    12 
    13     var parent = new Parent("MyParent");
    14     var child = new Child("MyChild");
    15 
    16     console.log(parent.getName());      //MyParent
    17     console.log(child.getName());       //MyChild

    //这样我们就只需要在子类构造函数中执行一次父类的构造函数,同时又可以继承父类原型中的属性,这也比较符合原型的初衷,就是把需要复用的内容放在原型中,我们也只是继承了原型中可复用的内容。

    这里如果按序打印 parent, child, Parent, Child,则输出如下:

    然后面试官又问如果只想改变子类的原型而不影响父类呢……我想了半天不知道怎么写,但是因为之前看过,就讲了下思想,就是用一个中间变量来存储其原型,然后给子类new一个……正确方法如下:

    //临时构造函数模式(圣杯模式)(别问我为什么会有一个名字这么中二的方法我也不知道)
    //上面借用构造函数模式最后改进的版本还是存在问题,它把父类的原型直接赋值给子类的原型,这就会造成一个问题,就是如果对子类的原型做了修改,那么这个修改同时也会影响到父类的原型,进而影响父类对象,这个肯定不是大家所希望看到的。为了解决这个问题就有了临时构造函数模式。
    var Parent = function(name){
        this.name = name || 'parent' ;
    } ;
    Parent.prototype.getName = function(){
        return this.name ;
    } ;
    Parent.prototype.obj = {a : 1} ;
    
    var Child = function(name){
        Parent.apply(this,arguments) ;//通过apply调用父类的构造函数来进行相同的初始化工作
    } ;
    var F = new Function();
    F.prototype = Parent.prototype ;
    Child.prototype = new F() ;
    //通过在父类原型和子类原型之间加入一个临时的构造函数F,切断了子类原型和父类原型之间的联系,这样当子类原型做修改时就不会影响到父类原型。
    
    var parent = new Parent('myParent') ;
    var child = new Child('myChild') ;
    
    console.log(parent.getName()) ; //myParent
    console.log(child.getName()) ; //myChild

    打印结果:

    可以看到Child的实例child会多嵌套一层。

    然后我发现其实可以不使用中间变量F,直接Child.prototype  = new Parent();也可以。

    var Parent = function(name){
        this.name = name || 'parent' ;
    } ;
    Parent.prototype.getName = function(){
        return this.name ;
    } ;
    Parent.prototype.obj = {a : 1} ;
    
    var Child = function(name){
        Parent.apply(this,arguments) ;//通过apply调用父类的构造函数来进行相同的初始化工作
    } ;
    Child.prototype = new Parent() ;
    
    Child.prototype.sayHi  = function(){
        alert("hi!");
    }
    
    var parent = new Parent('myParent') ;
    var child = new Child('myChild') ;
    
    console.log(parent.getName()) ; //myParent
    console.log(child.getName()) ; //myChild
    parent.sayHi();     //not a function 报错。说明子类的prototype不会影响到父类

    这样的问题是:父类构造函数被执行了两次,一次是在子类构造函数中,一次在赋值子类原型时,这是很多余的。

    那么是否可以不使用apply,直接var Child  = new Function(); Child.prototype = new Parent();呢……这样绝对不可以!

    //这种方法是错误的!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

    var Parent = function(name){ this.name = name || 'parent' ; } ; Parent.prototype.getName = function(){ return this.name ; } ; Parent.prototype.obj = {a : 1} ; var Child = new Function(); Child.prototype = new Parent() ; var parent = new Parent('myParent') ; var child = new Child('myChild') ; console.log(parent.getName()) ; //myParent console.log(child.getName()) ; //parent

    //child是Function对象,其中并没有name属性,所以在new一个Child时,括号内的参数是无效的!!!!

    那这种方法不是更容易吗……有什么缺点呢?console.log打印一下parent和child,以及Parent和Child,就会发现问题……

    可以看到,打印Parent中是有name属性的,而Child里没有name这一属性。而若是看parent和child两个实例,就可以看到其实例也没有name属性,name是原型的属性,这个意思就是说,如果Child有多个实例,多个实例的name属性都会指向同一个name,而不是私有的。

    所以方法就是1和2了  

    2. 对象冒充

     1        function Parent(name){
     2             this.name = name;
     3             this.getName = function(){
     4                 return this.name;
     5             }
     6         }
     7         function Child(name,password){
     8             //通过以下3步实现将Parent属性和方法追加到Child中,从而实现继承
     9             //第一步:this.method是作为一个临时的属性,并且指向Parent所指的对象
    10             //第二步:执行this.method方法,即执行Parent所指向的对象函数
    11             //第三步:销毁this.method属性,即此时Child就已经拥有了Parent的所有属性和方法
    12             this.method = Parent;
    13             this.method(name);
    14             delete(this.method);
    15 
    16             this.password = password;
    17             this.world = function(){
    18                 alert(this.password);
    19             }
    20         }
    21         var child = new Child("Mychild","123456");
    22         console.log(child.getName());       //Mychild
    23         child.world();                      //123456

    此外可参考博文:http://blog.csdn.net/james521314/article/details/8645815

  • 相关阅读:
    random模块学习笔记
    python3 控制结构知识及范例
    eclipse运行python 安装pydev 版本匹配问题
    接口自动化CSV文件生成超长随机字符串--java接口方法
    lucene 3.0 + 盘古分词 + 关键字高亮 + 分页的实现与demo
    Loading a Different jQuery Version for IE6-8
    选择排序和冒泡排序
    Bootstrap Tabs with AJAX snippet
    jquery.qrcode.js
    validator.w3.org for html5
  • 原文地址:https://www.cnblogs.com/haoyijing/p/5760586.html
Copyright © 2011-2022 走看看