JS高级-3(继承,类)

1.继承

1.1继承

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>

<body>
    <script>
    // 继承: 一个对象可以去使用另外一个对象的成员
    // 继承的好处:有利于代码的复用


    /*var lw = {
        skill: "*",
        age: 28,
        sayHi: function () {
            
        }
    }

    function Person() {}
    var xm = new Person();

    // 如何实现让xm可以使用到lw对象上的skill属性???
    console.log(xm.skill); // ==> **/


    // 实现继承的方式
    // 1. 原型链继承:实例对象可以直接去访问(继承到了)原型对象上的任意成员

    function Person(){

    }
    
    Person.prototype.sayHi = function () {
        console.log("hi");
    }
    Person.prototype.running = function () {
        console.log("running man");
    }
    Person.prototype.work = function () {
        console.log("work");
    }

    var p = new Person();
    console.log(p);
    p.sayHi()

    </script>
</body>

</html>

1.2原型链继承-优化写法

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>

<body>
    <script>
    // 实现继承的方式
    // 1. 原型链继承:实例对象可以直接去访问(继承到了)原型对象上的任意成员

    // function Person(){

    // }
    
    /*// 虽然这种写法是可以实现效果的,但是添加的方法过多,写法重复、麻烦
    Person.prototype.sayHi = function () {
        console.log("hi");
    }
    Person.prototype.running = function () {
        console.log("running man");
    }
    Person.prototype.work = function () {
        console.log("work");
    }*/

    function Person(){}

    // 简化写法 ==> 原型替换
    // 问题: constructor属性丢失了
    // 解决方案: 给新的原型对象添加constructor属性,指向当前的构造函数
    Person.prototype = {
        // 手动补上的
        constructor: Person,

        sayHi: function () {
            console.log("hello");
        },
        work: function () {
            console.log("work");
        },
        running: function () {
            console.log("running man");
        }
    }

    var p = new Person();
    
    // 沿着对象的原型链往上查找
    // p对象的原型链:
    //  p ==> Person.prototype({xxxx}) ==> Object.prototype ==> null;
    console.log(p.constructor); // Person

    /*console.log(p);
    p.sayHi()
    p.running()*/


    
    
    // 小结;
    //  原型链继承: 给原型对象添加的方法,实例对象是可以直接继承到
    //  写法:
    //   1. Person.prototype.sayHi = function(){}  问题:添加的方法比较多的时候,写法重复
    //   2. 原型替换   Person.prototype = { xxx }  问题: 造成了constructor属性丢失了
    //      解决: 手动给新的原型对象添加constructor属性
    </script>
</body>

</html>

1.3借用构造函数继承

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>
<body>
    <script>
        // 借用构造函数继承
        function Person(name, age, gender){
            this.name = name;
            this.age = age;
            this.gender = gender;
        }

        function Chinese(name, age, gender, skin) {
            // 以下三个name, age, gender属性已经在构造函数Person内写过了
            // 如何优化?? ==> 借用构造函数Person来继承里面的属性
            // 借用: call apply 作用一样,区别传参

            // Person.call(this, name, age, gender);
            Person.apply(this, [name, age, gender]);
            // 1. call可以调用函数,Person被调用了
            //  Person函数内的this指向谁?
            //  Person函数的三个形参的值是什么?
            // 2. Person函数内的this指向call的第一个参数, 指向了xm
            // 3. call除了第一个参数外,其他所有的参数都是给Person函数传递实参的
            
            /*this.name = name;
            this.age = age;
            this.gender = gender;*/

            this.skin = skin;
        }
        var xm = new Chinese("xm", 20, "male", "黄");
        console.log(xm);
    </script>
</body>
</html> 

1.4组合继承

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>
<body>
    <script>
        // 组合继承:
        //  1. 原型链继承  ==> 继承到Person的prototype上的方法
        //  2. 借用构造函数继承 ==> 继承到Person构造函数内添加的属性
        

        function Person(name, age, gender){
            this.name = name;
            this.age = age;
            this.gender = gender;
        }
        
        Person.prototype.sayHi = function () {
            console.log("hello, 我是 " + this.name);
        }

        function Chinese(name, age, gender, skin) {
            // 借用构造函数继承 ==> 继承到name、age。gender属性
            Person.apply(this, [name, age, gender]);
            this.skin = skin;
        }
        
        // 原型链继承 ==> 原型替换写法
        Chinese.prototype = Person.prototype;

        // 演示以上原型替换写法的问题: 
        // 想要修改Chinese.prototype,其实本质上修改了Person.prototype
        Chinese.prototype.color = "lime";
        // 想要给Chinese.prototype添加sayHi方法,但是本质上是修改了Person.prototype原型对象上的sayHi方法。
        Chinese.prototype.sayHi = function () {
            console.log("hi");
        }

        var xm = new Chinese("xm", 20, "male", "黄");
        console.log(xm);

        // xm去使用sayHi方法,沿着xm的原型链来找方法。
         // xm的原型链:
         //  xm ==> Chinese.prototype(本质上Person.prototype) ==> Object.prototype ==> null;
        
        // 核心的点: 让Person的prototype出现在xm的原型链上
        //  把Chinese的prototype换成Person的prototype
        
        xm.sayHi();
    </script>
</body>
</html>

1.5组合继承-优化

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>
<body>
    <script>
        // 组合继承:
        //  1. 原型链继承  ==> 继承到Person的prototype上的方法
        //  2. 借用构造函数继承 ==> 继承到Person构造函数内添加的属性

        function Person(name, age, gender){
            this.name = name;
            this.age = age;
            this.gender = gender;
        }
        
        Person.prototype.sayHi = function () {
            console.log("hello, 我是 " + this.name);
        }

        function Chinese(name, age, gender, skin) {
            // 借用构造函数继承 ==> 继承到name、age。gender属性
            Person.apply(this, [name, age, gender]);
            this.skin = skin;
        }
        
        // 原型链继承 ==> 原型替换写法
        // Chinese.prototype = Person.prototype;
        /*var p = new Person(); // p 是Person的实例对象
        Chinese.prototype = p;*/
        
        // 上面两行代码的简化写法
        Chinese.prototype = new Person();// p 是Person的实例对象

        Chinese.prototype.color = "lime";  // 本质上其实是修改了p

         // xm的原型链:
         //  xm ==> Chinese.prototype(本质上实例对象p)==> Person.prototype ==> Object.prototype ==> null;

        var xm = new Chinese("xm", 20, "male", "黄");
        console.log(xm);

        // 优化后的效果
        // 1. xm还可以继续使用sayHi方法
        // 2. 修改Chinese.prototype,不会影响到Person.prototype

        // xm去使用sayHi方法,沿着xm的原型链来找方法。
        
        
        // 核心的点: 让Person的prototype出现在xm的原型链上
        //  把Chinese的prototype换成Person的prototype
        
        xm.sayHi();
    </script>
</body>
</html>

2.类

2.1ES6的class

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>
<body>
    <script>
        // 继承 ES6 class类  类的继承很简单
        /*function Person(){}
        var p = new Person();*/
        
        /*// 类的语法  class 类{}
        class Person{}
        // 通过类来创建实例对象, new 类()
        var p = new Person();
        console.log(p);*/


        // 给类的实例对象添加属性 ==> 在类的内部通过constructor函数来进行添加

        class Person{
            constructor(name, age, gender){
                this.name = name;
                this.age = age;
                this.gender = gender;

                // 如此添加方法可以,但是容易造成内存浪费问题
                // 要添加方法,需要给原型对象添加
                /*this.sayHi = function () {
                    console.log("hi");
                }*/
            }
            
            // 在类的{}里面写的方法,是添加在原型对象上了
            sayHi() {
                console.log("hello");
            }

            work(){
                console.log("work save money");
            }
        }
        var p = new Person("xm", 20, "male");
        console.log(p);
        p.sayHi();
        p.work();

        
        // ES6 类 创建对象
        // 定义:class 类{}
        // 创建实例: new 类();
        // 给类的实例添加属性: 类的内部通过constructor函数来添加
        // 给类的实例添加方法: 给原型对象上添加,把方法直接写在类的里面

        /*class Chinese {
            constructor(){
                // 实例添加属性
            }

            // 给原型对象添加方法
            sayHi(){//...}
        }*/

        // 类 语法糖
        //  类的本质还是构造函数 + 原型对象
    </script>
</body>
</html> 

2.2类的继承

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>

<body>
    <script>
    // 类的继承语法:
    //  class 子类 extends 父类{}

    // 父类
    class Person {
        constructor(name, age, gender) {
            this.name = name;
            this.age = age;
            this.gender = gender;
        }

        sayHi() {
            console.log("hello");
        }
    }

    // 子类
    // 子类是继承到父类上的属性和原型上的方法
    class Chinese extends Person {
        // 处理skin属性 ==> 需要在constructor函数内来添加
        /*constructor(name, age, gender, skin){
            // 在子类的constructor函数中,必须优先调用super();
            // super函数表示的是父类的构造函数
            super(name, age, gender);
            this.skin = skin;
        }*/

        constructor(name, age, gender, skin) {
            // 只要在子类中, 写了constructor函数,必须去做: 在constructor函数内优先去调用super函数
            super(name, age, gender);
            this.skin = skin;
        }
    }

    // 实例化子类
    var p = new Chinese("xm", 20, "male", "黄");
    console.log(p);
    p.sayHi();

    

    // 小结: 
    //  类的继承语法: class 子类 extends 父类
    //   子类就已经继承到父类的属性和原型上的方法
    
    // 子类中添加自己的属性,写constructor构造函数
    // 注意点: 必须优先调用super函数(父类的构造函数)
    //      然后在去添加自己的属性

    </script>
</body>

</html>

上一篇:radio单选框学习


下一篇:MySQL常见约束(主键,外键,默认,非空,检查,唯一)