• javascript中的继承[二] 基于构造函数(《ObjectOriented JavaScript》第六章)


    上篇末尾遗留的解释:

    js中函数也是对象,因此上图一共有六个对象

    其中Person 和 Coder 是函数,他们有prototype 属性

    Person的prototype属性是原生的,是一个内部生成的obj,有toString方法

    Coder的portotype属性认为的指向 Person的一个实例person

    其他的不赘述。

    (一)把对象共享的属性放在构造函数的prototype属性中

    前一篇文章介绍原型链的过程,我们会发现,没有必要给所有的子对象都添加相同的方法,只要构造函数的prototype属性中有这个方法即可。

    /*
    function Person(name){
        this.name = name;
        this.sayHello = function(){alert(this.name);};
    }
    */
    
    function Person(name){
        this.name = name;
    }
    Person.prototype.sayHello = function(){
        alert(this.name);
    };
    
    var p = new Person("jim");
    p.sayHello();

    这样,就不需要为每个对象添加sayHello方法了。

    function Coder(language,name){
       this.language = language;
           this.name = name;
    }
    
    Coder.prototype = new Person("无名");
    Coder.prototype.code = function(){
        alert("i am a "+this.language+" coder");
    };
    
    var c1 = new Coder("js","jim");
    c1.sayHello();
    c1.code();

    这样,Coder的每个对象也都可以访问到 Person中的方法了

    c1本身没有sayHello方法,会到Coder的prototype属性中找。而这个属性指向了Person的一个实例,这个实例当然有办法执行sayHello方法咯

    好处:

    1.不用为每个对象实定义各自的方法

    2.“子类”能够继承父类的方法

    坏处:

    1.Corder.prototype属性中含有一些不必要的私有属性,如name

    (二)单继承 prototype

    出于提高效率的考虑,可不可以Coder.prototype 指向 Person.prototype 呢?

    /*
    function Person(name){
        this.name = name;
        this.sayHello = function(){alert(this.name);};
    }
    */
    
    function Person(name){
        this.name = name;
    }
    Person.prototype.sayHello = function(){
        alert(this.name);
    };
    
    function Coder(language,name){
       this.language = language;
           this.name = name;
    }
    
    Coder.prototype = Person.prototype;
    Coder.prototype.code = function(){
        alert("i am a "+this.language+" coder");
    };
    
    var c1 = new Coder("js","jim");
    c1.sayHello();
    c1.code();

    这样做的好处:

    1.少实例化一个对象

    2.找sayHello方法时,原型链更短

    坏处:破坏了“父类”Person的接口

    (三)使用临时构造函数,只继承公共方法,不继承私有属性

    function Person(name){
        this.name = name;
    }
    Person.prototype.sayHello = function(){
        alert(this.name);
    };
    
    function Coder(language,name){
       this.language = language;
           this.name = name;
    }
    
    var F = function(){};
    F.prototype = Person.prototype;
    Coder.prototype = new F();
    
    Coder.prototype.code = function(){
        alert("i am a "+this.language+" coder");
    };
    
    var c1 = new Coder("js","jim");
    c1.sayHello();
    c1.code();

    好处:Coder.prototype 不含有 name等私有属性

    (四)封装上面的过程

    function extend(Child,Parent){
        var F = function(){};
        F.prototype = Parent.prototype;
        Child.prototype = new F();
        Child.prototype.constructor = Child;
    }

    通过这个方法,我们就可以很方便地继承一个“类”

    最后一行代码需要解释一下

    原始的构造函数的prototype属性中的constructor指向构造函数,这个属性,是的实例化对象obj可以通过 obj.constructor调用构造函数,再次构造新的对象。

    开发实践中在一定的情形下会出现这种情况,因此当我们把prototype属性指向其他对象时,我需要人工的声明下constructor属性。

    现在我们看看 Coder 通过 extend函数如何 继承

    function extend(Child,Parent){
        var F = function(){};
        F.prototype = Parent.prototype;
        Child.prototype = new F();
        Child.prototype.constructor = Child;
    }
    function Person(name){
        this.name = name;
    }
    Person.prototype.sayHello = function(){
        alert(this.name);
    };
    
    function Coder(language,name){
       this.language = language;
           this.name = name;
    }
    
    extend(Person,Coder);
    Coder.prototype.code = function(){
        alert("i am a "+this.language+" coder");
    };
    
    var c1 = new Coder("js","jim");
    c1.sayHello();
    c1.code();
    var c2 = new c1.constructor("php","lily");
    c2.code();

    好处:封装了extend方法,方便。YUI的extend方法就是这么实现的

    我为了突出重点,故意疏漏了 子类如何方法父类的方法属性( 如果有需要的话)。

    到目前为止,我们都是使用原型链的方式实现继承,除了原型链还有别的途径吗??有的,通过复制prototype属性。

    原型链继承的实现列表

    1.把对象共享的属性放在构造函数的prototype属性中

    2.单继承 prototype(复制prototype)

    3.使用临时构造函数,只继承公共方法,不继承私有属性

    4.封装3的过程

    (五)通过复制prototype属性实现继承

    我们除了通过原型链 实现 继承,还可以让Child 复制 Parent的 的prototype属性,这样做的好处:

    Child的prototype没有链,有2.单继承的优点,也不会修改Parent的prototype,也不会继承私有方法

    看似聚集了上面四种方法的所有优点

    如何复制prototype属性呢?我们实现一个extend2的方法:

    /*
    function extend(Child,Parent){
        var F = function(){};
        F.prototype = Parent.prototype;
        Child.prototype = new F();
        Child.prototype.constructor = Child;
    }
    */
    
    function extend2(Child,Parent){
        var p = Parent.prototype;
        var c = Child.prototype;
        for(var i in p){
            c[i] = p[i];
        }
    }

    我们没有把Child的原型对象指向新的实例,只是复制了Parent.prototype中的所有属性,一次不需要再人工赋值constructor属性

    function Person(name){
        this.name = name;
    }
    Person.prototype.sayHello = function(){
        alert(this.name);
    };
    
    function Coder(language,name){
       this.language = language;
           this.name = name;
    }
    
    extend2(Person,Coder);
    Coder.prototype.code = function(){
        alert("i am a "+this.language+" coder");
    };
    
    var c1 = new Coder("js","jim");
    c1.sayHello();
    c1.code();
    var c2 = new c1.constructor("php","lily");
    c2.code();

    和之前通过extend实现继承的代码基本一致,只是多了一个2.

    这样做的好处:

    没有链了,貌似可以提高效率

    坏处:

    复制属性,会带来一些不必要的内存开销。

    但是,prototype属性大部分是方法,这种情况下,只是多了一个指针指向方法而已,并没有真正重新实现一次方法。

    这五种方式实现继承都基于一种假设:我们的对象实例都是通过构造函数生成的。

    如果我们不用构造函数呢,还可以做些别的事情吗??详看后文




    苦逼码农一个,
    人力资源管理专业本科毕业,
    懂点c#,
    懂点javascript,
    懂点sql,
    懂点设计模式
    ...

    @我是赵六六

    q:329952402

  • 相关阅读:
    [python]python学习笔记(七)——加密
    Android 实现ListView的A-Z字母排序和过滤搜索功能,实现汉字转成拼音 .
    Android 关于汉字转拼音的工具类Pinyin4jUtil 的使用说明
    20条技巧,让Chrome超越Firefox
    Android 内存优化
    WebView详解
    Android 获取手机通讯录信息 — 姓名和号码
    Android 获取手机通讯录信息 — 头像、姓名和A-Z的快速查询
    Android 快速开发框架AFinal
    Android 滑动改变视频音量和视频缩略图
  • 原文地址:https://www.cnblogs.com/acjialiren/p/2983260.html
Copyright © 2020-2023  润新知