JavaScript---继承

  JavaScript---继承

      JavaScript语言的继承机制---由于JavaScript没有‘类(class)’和‘实例(instance)’的概念,他是靠‘原型链(prototype  chain)’模式来实现继承的

  要理解JavaScript的继承机制,首先,要清楚这几个概念:构造函数,实例对象,prototype,constructor、__proto__  以及他们之间的关系。

      构造函数:用来初始化新创建的对象的函数是构造函数。(你可以把构造函数看成是“类”)

      实例对象:通过构造函数的new操作创建的对象是实例对象。可以用同一个构造函数,构造多个实例对象。

      prototype:每个函数(当然包括构造函数)都有一个prototype属性,它是一个对象。我们称它为‘原型对象’  prototype:{...}

      constructor:每个对象都有一个constructor属性,它是一个函数:constructor:fn(){...} 它的作用就是指向该原型对象对应的构造函数。由于实例对象可以继承原型对象的属性,所以实例对象也拥有constructor属性,同样指向原型对象对应的构造函数

      __proto__:每个实例对象都有一个proto属性,指向创建该实例对象的构造函数的原型对象(可以理解为 实例对象---》构造函数的原型对象)

  熟练使用JavaScript的继承必须要对这几个概念烂熟于心。

    接下来结合图示来分析一下。

  

 

    要想清楚的了解JavaScript的继承机制,这些概念是必须烂熟于心的。

    

    JavaScript的继承 ---指的是子类继承父类的属性和方法

    JavaScript的继承特点:1.子类拥有父类所有的属性和方法(代码复用);2.子类可以扩展自己的属性和方法(更加灵活);3.子类可以重写父类的方法

 

    JavaScript的继承方式

      1.组合继承

        

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>组合继承法</title>
    <script>
        function Person(name,age,gender,geyan){
            this.name = name;
            this.age = age;
            this.gender = gender;
            this.geyan = geyan;
        }

        Person.prototype.say = function(){
            console.log(`我叫${this.name},${this.gender},我今年${this.age}岁,我的人生格言是:${this.geyan}`);
        }


        var p1 = new Person('lx',18,'','我姓谢,王菲的哪个谢');
        var p2 = new Person('lw',45,'','你有困难我帮忙,我住隔壁,我姓王');
        p1.say();
        p2.say();


        function Student(){
            // 借用构造函数法
            // Person.call(this,name,age,gender,geyan)
            Person.apply(this,arguments);
        }


        //原型链继承法
        Student.prototype = new Person();
        var s1 = new Student('小明', 12, '', '姐姐,约吗');
        s1.say();
        console.log(s1);
    </script>
</head>
<body>
    
</body>
</html>

  chrome显示如下:

 

  组合继承主要使用:1.借用构造函数法--使用call方法或apply方法借用父类的属性,使子类可以使用。 2.原型链继承法---将父类的实例对象赋给子类的原型对象,这样,子类的原型对象就继承到了父类的原型对象里的方法(子类原型对象---》父类原型对象)

  组合继承的弊端:1.多次执行了父类构造函数  在我们的例子中, 每创建一个子类的实例sn,都要调用一次父类构造函数 ,很麻烦。  2.在原型对象里生成多余的属性  原因在于原型链继承这一步中,父类的实例对象的属性也被子类的原型对象继承了。

  知道他的弊端之后,就能加以改进了:将原型链继承法用新的方法替代,这个新的方法叫做:原生式继承法。这个方法不会生成多余的属性

    来看改进过的代码:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>组合继承法</title>
    <script>
        function Person(name,age,gender,geyan){
            this.name = name;
            this.age = age;
            this.gender = gender;
            this.geyan = geyan;
        }

        Person.prototype.say = function(){
            console.log(`我叫${this.name},${this.gender},我今年${this.age}岁,我的人生格言是:${this.geyan}`);
        }


        var p1 = new Person('lx',18,'','我姓谢,王菲的哪个谢');
        var p2 = new Person('lw',45,'','你有困难我帮忙,我住隔壁,我姓王');
        p1.say();
        p2.say();


        function Student(){
            // 借用构造函数法
            // Person.call(this,name,age,gender,geyan)
            Person.apply(this,arguments);
        }


        //原生式继承法
        function object(o){
            function F(){}
            F.prototype = o;
            return new F();
        }
        Student.prototype = object(Person.prototype);
        var s1 = new Student('小明',12, '', '姐姐,约么?');
        s1.say();
        console.log(s1);
    </script>
</head>
<body>
    
</body>
</html>

 

  在chrome中显示:

   原生式继承法的精髓在于:直接继承父类的原型,而不是向原型链继承那样继承整个父类。但这样又带来了一个新的问题:每次继承都要写一长串的代码。

怎么偷懒? 好在ES5给我们拓展了关于原型的继承方法----子类.prototype = Object.create(父类.prototype);

   再看一下改进的代码:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>组合继承法</title>
    <script>
        function Person(name,age,gender,geyan){
            this.name = name;
            this.age = age;
            this.gender = gender;
            this.geyan = geyan;
        }

        Person.prototype.say = function(){
            console.log(`我叫${this.name},${this.gender},我今年${this.age}岁,我的人生格言是:${this.geyan}`);
        }


        var p1 = new Person('lx',18,'','我姓谢,王菲的哪个谢');
        var p2 = new Person('lw',45,'','你有困难我帮忙,我住隔壁,我姓王');
        p1.say();
        p2.say();


        function Student(){
            // 借用构造函数法
            // Person.call(this,name,age,gender,geyan)
            Person.apply(this,arguments);
        }


        //ES5的原型使继承法
        Student.prototype = Object.create(Person.prototype);

        var s1 = new Student('小明',12,'','姐姐,约么?');
        s1.say();
        console.log(s1);
    </script>
</head>
<body>
    
</body>
</html>

  

  在chrome中显示:

这种原型式继承法+借用构造函数法的强力组合就是JavaScript继承方式的第2种方法 叫做寄生继承。这也是最终推荐的继承方式。

 

 

 

 

你以为结束了吗??

 

 

 

 

 

 

 

    讲完了ES5,怎能不讲讲ES6?  ES6给我们准备了一个“大礼包”!!

      开头说到,JavaScript没有“类”的概念。现在有了(JavaScript一直在成长啊)!!ES6中用关键字 class 来定义一个类

  先上代码:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>ES6中的继承方式</title>
    <script>

        // 类: 使用class定义了一个类 Person
        class Person{

            // 构造函数  所有的属性都放在constructor函数里(模仿java)
            constructor(name,age){
                this.name = name;
                this.age = age;
            }

            // 所有的方法写在函数constructor外 注意:并不需要声明方法 直接 say(){...}的形式 相当于 Person.prototype.say = function(){...}
            say(){
                console.log('say,say');
            }


            // 静态方法 只会被子类继承, 不会被子类的实例继承
            static sing(){
                console.log(`我叫${this.name},我会唱歌`);
            }
        }

        

        // Person.prototype.say = function(){}

        var p1 = new Person('lx',18);
        p1.say();


        // 静态方法的调用
        Person.sing();

    //使用extends去继承父类   class 子类 extends 父类{...}
        class Student extends Person{
            constructor(name,age){
                super(name,age);
            }
        }

        var s1 = new Student('小红',12);

        Student.sing();

        s1.say()


        console.log(p1,s1)
    </script>
</head>
<body>
    
</body>
</html>

 

  在chrome中显示:

 

是不是很强大!!!                           考虑到部分浏览器还未兼容ES6的标准。所以还是推荐使用ES5的寄生继承。

 

JavaScript的继承机制就暂告一段落了。有问题以后补充                  ----2017-03-21-20:10

 

posted @ 2017-03-21 20:12  游鱼与渔  阅读(235)  评论(0编辑  收藏  举报