zoukankan      html  css  js  c++  java
  • javascript中的继承用法

    本文实例汇总了javascript关于继承的用法,希望本文所述对大家的javascript程序设计有所帮助。分享给大家供大家参考。具体如下:
    代码如下:

    /**
    * 实现子类继承父类,但不会产生多余的属性和方法
    * @returns {Function}
    */
    define(function(){
    return function(subType, superType){
    var proto = new Object(superType.prototype);
    proto.constructor = subType;
    subType.prototype = proto;
    };
    });
    //——————————————————————————
    define(function(){
    function ostring(s)
    {
    this.str = s;
    this.length = this.str.length;
    }
    ostring.prototype.show = function(){
    alert(this.str);
    };
    return ostring;
    });
    //——————————————————————————
    define(['inherit', 'ostring'], function(inherit, ostring){
    function wstring(s){
    //用call实现调用父类构造函数
    ostring.call(this, s);
    this.chlength = 2 * s.length;
    }
    //继承其他的属性
    inherit(wstring, ostring);
    wstring.prototype.add = function(w)
    {
    alert(this.str + w);
    };
    return wstring;
    });

    一、用function实现:

    function Person(name) {
        this.name = name;
    }
    Person.prototype.getName = function() {
        return this.name;
    }
    function Author(name, books) {
        this.inherit=person;
        this.inherit(name);
        this.books = books;
        
    }
    var au=new Author("dororo","Learn much");
    au.name

    或者同等效力的:

    function Person(name) {
        this.name = name;
    }
    Person.prototype.getName = function() {
        return this.name;
    }
    function Author(name, books) {
        Person.call(this, name);
        this.books = books;
        
    }
    var au=new Author("dororo","Learn much");
    au.getName

    由于这只是将this作为参数,调用父类Person的构造函数,把赋予父类的所有域赋予Author子类,所以任何父类Person构造函数之外的定义的域(原型prototype),子类都不会继承。所以上面例子中,au.getName将是没有被定义的(undefined),因为getName是在Person的原型对象中定义的。

    而且,子类的构造函数要在定义自己的域之前调用父类构造函数,免得子类的定义被父类覆盖掉。也就是说,Author定义属性book要在Person.call之后,否则会被Person中属性覆盖。同时,在子类中也最好不要用prototype来定义子类的函数域,因为在一个子类被new,实例化之后就要执行prototype,然后才是调用父类的构造函数,这样也容易被父类的属性覆盖掉。

    二、用prototype实现:

    function Person(name) {
        this.name = name;
    }
    Person.prototype.getName = function() {
        return this.name;
    }
    function Author(name, books) {
        this.books = books;  
    }
    Author.prototype=new Person(name);
    Author.prototype.constructor=Author;
    Author.prototype.getBooks = function() {
        return this.books;
    }
    var au1=new Author("dororo1","Learn much");
    var au2=new Author("dororo2","Learn less");
    alert(au1.getName());
    alert(au2.getName());

    这种方法避免了function实现中,无法继承prototype的问题。因为 Author.prototype=new Person(name);new Person()实例会调用Person构造和原型的所有属性。但是缺点是已经实例化了Author.prototype。所以当子类实例化的时候,所有非基本数据类型都是reference copy。所以上面例子中,无论实例au1,还是au2返回的值都是dororo1.

    三、用“混合”实现

    function Person(name) {
        this.name = name;
    }
    Person.prototype.getName = function() {
        return this.name;
    }
    function Author(name, books) {
        this.base = new Person(name);
        for(var key in this.base){
            if(!this[key]){
               this[key]=this.base[key];
               }
               }
        this.book=books;
    }
    var au1=new Author("dororo1","work");
    var au2=new Author("dororo2","play");
    alert(au1.getName());
    alert(au2.getName());
    au1.book;
    au2.book;
     

    属于扩展,把父类的所有域都拷贝到子类。完全没有上述两方面的问题。
    寄生组合模式)

    JS的继承包括属性的继承和方法的继承,他们分别通过不同的方法来实现。
    1.属性的继承

    属性的继承通过改变函数的执行环境来实现的。而改变函数的执行环境可以使用call()和apply()两种方法来实现。

    我们首先创建一个Animal“类”(因为JS中没有类的概念,这里只是一个模拟,它实际上只是一个Function函数对象)。

    function Animal(typeName) {
    //为当前方法的执行环境(this)添加一个属性typeName
    //但是执行环境(this)要执行这个函数的时候才能确定
    this.typeName = typeName;
    this.colors = ["red","while"];
    }
    //想函数的原型里 添加 两个(对象共享的)的方法
    Animal.prototype.Shout = function () { alert("我是:--" + this.typeName);};
    Animal.prototype.Eat = function () { alert("我是:--" + this.typeName) };
    //--定义一个狮子--“类”(其实就是一个函数)
    function Lion(tn) {
    //--执行Animal方法,并通过apply的第一个参数 修改了Animal的执行环境为Lion的this
    //同样的,Lion的this,也要在执行的时候才能确定是谁
    Animal.apply(this,["狮子"]);//--继承了父类的变量属性,this因为是new了Lion,this是Lion
    }
    Lion.prototype = Animal.prototype; //继承父类的方法,搞定--但是这写不好,当子类再添加方法时候,父类同样也有此方法,这是指针引用
    Lion.prototype.Hunt = function () {
    alert("我是:狮子,我要去捕猎~~·~");
    }
    var aminm = new Animal();
    aminm.Hunt(); //---可以访问到子类的方法,这样就不好了
    //----那么如何解决这个问题呢》??????
    //---解决方案:继承方法时候可以这样写:
    Lion.prototype = new Animal();//继承父类的方法,把Animal对象赋给了prototype原型,其实它里面也有属性
    var lion = new Lion(); //new 关键字除了创建的,还会修改Lion对象的执行环境为Lion对象本身
    // ---换句话说,就是new完了之后,Lion函数里的this就是Lion函数本身了,然后调用Lion函数

    new关键字作用解析:

    而new关键字是十分伟大的,在上段代码中,new关键字完成了以下几项工作:

    1. 开辟堆空间,以准备存储Lion对象
    2. 修改Lion对象本身的执行环境,使得Lion函数的this指向了Lion函数对象本身。
    3. 调用Lion“类”的“构造函数”,创建Lion对象
    4. 将Lion函数对象的堆地址赋值给变量l,这个时候l就指向了这个Lion函数对象
      lion.Shout();
      lion.Eat();

      但是这种继承有个缺点:就是父类的构造函数的被调用了两次,call一次,然后new又一次。

  • 相关阅读:
    写给QA/软件测试新人
    互联网产品线上故障管理规范
    爬了世纪佳缘后发现了一个秘密,世纪佳缘找对象靠谱吗?
    网传美团今年应届生年薪 35w+,严重倒挂老员工,为什么互联网大厂校招的薪资一年比一年高?...
    MySQL大表优化方案
    步入AI领域2年连升3级,我只是找对了学习方法而已……
    BZOJ 4008 亚瑟王(概率DP 奥妙重重)
    BZOJ 4318 OSU! (概率DP)
    BZOJ 3812 主旋律 (状压DP+容斥) + NOIP模拟赛 巨神兵(obelisk)(状压DP)
    BZOJ 4145 [AMPPZ2014]The Prices (状压DP)
  • 原文地址:https://www.cnblogs.com/huhangfei/p/5000638.html
Copyright © 2011-2022 走看看