JavaScript - js进阶 - ES6面向对象

es6 class

es6的class 的出现 基本上可以替代了es5的构造函数和原型,使之代码结构上更加简洁。

关键字

  1. class
  2. 属性
  3. 方法
  4. 继承 extends
  5. 构造函数 constructor
  6. 方法重写 override:子类方法覆盖父类,super.父类方法()
  7. 父类的构造函数 super :子类有构造方法且使用this前,必须使用super()

ES6面向对象 - 类和成员

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8" />
        <meta http-equiv="X-UA-Compatible" content="IE=edge" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>ES6面向对象 - 类和成员</title>
    </head>
    <body></body>
    <script>
        // ES6中: 为了体现主体的概念(对象), 增加了一种结构: 类 class(抽象结构)
        // 语法使用没有什么区别
        // 1. 定义类(结构): 不会自动运行
        // 2. 调用类(实例化)

        // 定义类: class + 类名{}   类名: 大驼峰
        class Student {}

        // 实例化类: 得到具体的对象
        new Student();

        // 类成员: 直接归属类的{}管理的成员
        // 1. 属性: 变量, 保存数据, 但是不要关键字 let, 直接写名字即可, 赋值要用 = 等号
        // 2. 方法: 函数, 数据加工, 但是不要关键字 function, 直接写名字即可(自带function)
        class Teacher {
            // 属性
            workId; // 工号, 可以没有值(默认值是: undefined)
            age = 0; // 年龄, 可以有初始值: 大家都一样的时候

            // 方法
            work() {
                // this代表: new出来的对象(谁调用 代表谁)
                console.log("方法", this);
            }
            // 方法: 为了保证内存只有一份, 自动进了原型对象
        }

        // 实例化
        const t = new Teacher();
        console.log(t);

        // 类就当做ES5中的构造函数: 也有原型对象
        console.log(Teacher.prototype);

        // 类中的属性和方法: new出来的对象, 可以直接使用
        console.log(t.workId, t.age);
        t.workId = "007";

        t.work();

        // 总结
        // 把ES6的类class, 当成ES5的构造函数即可
        // 为了方便: 不需要写this(属性: 也不需要let) 和 function(方法)
        // 使用类: 就跟ES5的实例化是一样的
    </script>
</html>

ES6面向对象-构造方法constructor

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8" />
        <meta http-equiv="X-UA-Compatible" content="IE=edge" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>ES6面向对象-构造方法constructor</title>
    </head>
    <body></body>
    <script>
        // ES6中有一个特殊的方法: 名字是固定的 constructor(), 当对象new出来之后: 立马会自动调用的方法

        class Student {
            name;

            // 学生应该有姓名和年龄
            constructor(name, age) {
                console.log("我被执行了");

                // 给当前对象添加属性
                this.name = name; // 修改属性: name属性(在外面定义没有意义)
                this.age = age; // 新增属性: age属性
            }
        }

        // new Student()                // 会触发构造函数的执行: new出来对象, 对象自动调用

        // 如何给构造方法传参呢? new 类名() , 这个括号()就是在调用constructor(), 用来给constructor传参的
        const s = new Student("百里", 20);
        console.log(s);

        // 构造方法作用: 初始化数据的(以后写类如果要初始化数据: 就要有构造方法constructor(); 如果没有数据要初始化: 不需要这个方法)

        // 构造方法: 只有new出来的对象自己调用的权利: 不能手动调用
        // s.constructor('妲己', 18)
        //  Class constructor Student cannot be invoked without 'new'
        //  类的constructor方法        不能   被  唤醒    没有    new
        // 类的constructor方法只能通过new出来的对象去唤醒(调用)

        // 总结
        // 构造方法用来初始化数据的: 本质就是ES5的构造函数(只是名字固定为: constructor, 目的就是为了让系统能够自动调用)
    </script>
</html>

ES6面向对象 - 继承

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8" />
        <meta http-equiv="X-UA-Compatible" content="IE=edge" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>ES6面向对象 - 继承</title>
    </head>
    <body></body>
    <script>
        // 继承: 实现代码的复用

        // 涉及继承: 项目级别

        // 前开设计的时候: 一定会对代码进行分层(找出上下级的关系)

        // 教务管理系统: 学生Student\老师Teacher\行政...\教室ClassRoom

        // 发现: 学生\老师\行政... 但凡是人,都有共同的内容: 姓名\年龄...数据(属性)  吃喝拉撒(行为: 方法)

        // 首先定义一个人类(上级类: 父类)
        class Person {
            name;
            age;

            chi() {
                console.log(this.name + "正在吃");
            }
            he() {
                console.log(this.name + "正在喝");
            }
        }

        // 定义下级类: 子类: class 子类 extends 父类
        class Student extends Person {}

        // 实例化子类(父类通常是用来提供公共代码, 不会被实例化)
        const s = new Student();
        console.log(s);

        // 对比一下ES5实现
        function Human() {
            this.name = undefined;
            this.age = undefined;
        }

        Human.prototype.chi = function () {};
        Human.prototype.he = function () {};

        // 子类继承
        function Teacher() {
            // 借调
            Human.call(this);
        }

        // 体现继承
        Teacher.prototype.__proto__ = Human.prototype;

        const t = new Teacher();
        console.log(t);

        // 总结
        // ES6的继承比ES5简洁方便, 更容易看懂
        // ES6继承: 属性被直接拿过来, 方法还在原型对象中: 只能用,不能拿过来
    </script>
</html>

ES6面向对象 - Tab栏切换 ( 案例 )

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8" />
        <meta http-equiv="X-UA-Compatible" content="IE=edge" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>ES6面向对象 - Tab栏切换</title>
    </head>
    <style>
        * {
            margin: 0;
            padding: 0;
        }

        ul {
            list-style: none;
        }

        .box {
            width: 400px;
            height: 300px;
            border: 1px solid #ccc;
            margin: 100px auto;
        }

        .hd {
            height: 45px;
        }

        .hd span {
            display: inline-block;
            /*将行内元素转换成行内块元素,宽高才起作用*/
            width: 90px;
            background-color: pink;
            line-height: 45px;
            text-align: center;
            cursor: pointer;
        }

        .hd span.current {
            /*交集选择器,标签指定式选择器*/
            background-color: purple;
            /*紫色*/
        }

        .bd li {
            height: 255px;
            background-color: purple;
            display: none;
            /*设置隐藏*/
        }

        .bd li.current {
            display: block;
            /*显示*/
        }
    </style>
    <script src="./js/Tab.js"></script>
    <body>
        <div class="box" id="box">
            <div class="hd">
                <span class="current">体育</span>
                <span>娱乐</span>
                <span>新闻</span>
                <span>综合</span>
            </div>
            <div class="bd">
                <ul>
                    <li class="current">我是体育模块</li>
                    <li>我的娱乐模块</li>
                    <li>我是新闻模块</li>
                    <li>我是综合模块</li>
                </ul>
            </div>
        </div>
    </body>
    <script>
        const tab = new Tab();

        console.log(tab);

        tab.mouseover();
    </script>
</html>

js

/**
 * 1. 先定义类: class
 * 2. 考虑: 是否存在数据需要初始化: 获取元素, 有初始化,增加一个方法: constructor()构造方法: 构造方法里面的数据,不是给自己用的, 是给其他方法用的(不能使用局部变量), 将数据保存到this,中, 所有方法中的this都是同一个对象
 * 2.* 考虑是否有灵活: 传参
 * 3. 考虑: 功能问题, 一个功能一个方法, mouseover鼠标移入效果: 一个独立的方法
 * */

class Tab {
    constructor() {
        this.spans = document.querySelectorAll(".hd span");
        this.lis = document.querySelectorAll(".bd li");
    }

    mouseover() {
        // 给所有的span做鼠标移入事件
        // console.log(this)

        // 都用箭头函数的目的: 保证this永远是一个东西
        this.spans.forEach((span, index) => {
            span.addEventListener("mouseover", () => {
                // 排他: 先统一后特殊

                // span和li干掉current类
                this.spans.forEach((item, i) => {
                    // item是每个span,i是每个span对应的下标
                    item.classList.remove("current");
                    this.lis[i].classList.remove("current");
                });

                // 当前span和当前li增加current类
                span.classList.add("current");
                this.lis[index].classList.add("current");
            });
        });
    }

    click() {
        // 给所有的span做鼠标点击事件
        // console.log(this)

        // 都用箭头函数的目的: 保证this永远是一个东西
        this.spans.forEach((span, index) => {
            span.addEventListener("click", () => {
                // 排他: 先统一后特殊

                // span和li干掉current类
                this.spans.forEach((item, i) => {
                    // item是每个span,i是每个span对应的下标
                    item.classList.remove("current");
                    this.lis[i].classList.remove("current");
                });

                // 当前span和当前li增加current类
                span.classList.add("current");
                this.lis[index].classList.add("current");
            });
        });
    }
}

ES6面向对象 - 重写override

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8" />
        <meta http-equiv="X-UA-Compatible" content="IE=edge" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>ES6面向对象 - 重写override</title>
    </head>
    <body></body>
    <script>
        // 重写: override, 子类拥有与父类同名的属性或者方法
        class Person {
            name = "Person";
            age = 60;

            work() {
                console.log(this.name + "种田为生");
            }

            other() {
                console.log("固定被继承方法");
            }
        }

        class Farmer extends Person {
            // 重写

            // 属性重写: 子类覆盖父类(永远找不到父类的)
            name = "Farmer";

            // 方法重写: 子类父类都存在, 访问只访问到自己的
            work() {
                console.log(this.name + "新农民挣钱");
            }
        }

        const f = new Farmer();
        console.log(f);

        console.log(f.name, f.age); // Farmer 60
        f.work(); // 新农民: 只访问到自己
        f.other(); // 固定被继承方法

        // 总结
        // 重写:override, 子类拥有与父类同名的属性或者方法
        // 属性重写: 覆盖效果(父类的没了)
        // 方法重写: 访问只访问到自己(父类还在)

        // 重写作用1: 就是为了"覆盖", 为了让父类的方法,特殊化(应用较多是 老旧系统维护)
    </script>
</html>

ES6面向对象 - 重写override - 调用父类被重写方法

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8" />
        <meta http-equiv="X-UA-Compatible" content="IE=edge" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>ES6面向对象 - 重写override - 调用父类被重写方法</title>
    </head>
    <body></body>
    <script>
        // 方法重写作用1: 完全覆盖父类方法(不用父类的)
        // 方法重写作用2: 在父类的基础上做扩展

        // 需要在子类重写父类的方法 中: 先调用父类的, 然后再执行自己其他代码
        class Person {
            work() {
                console.log("Person的work方法");
            }
        }

        class Farmer extends Person {
            // 重写功能的扩展
            work() {
                // 明确调用上级的被重写方法: super.被重写方法()
                super.work();

                console.log("Farmer修改的work方法");
            }
        }

        const f = new Farmer();
        f.work();

        // 如果是构造方法呢?
        // 1. 如果父类有构造方法: 子类可以重写, 但是重写后,必须先保证父类的构造方法运行

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

                console.log("Human的构造方法");
            }
        }

        class Student extends Human {
            constructor(name, age, stuno) {
                // 构造方法一旦被重写: 子类必须调用父类的构造方法(先调用, 后使用this)
                // 构造方法很特殊: 类中是固定名字的: constructor(), 所以调用也很特殊: super()
                super(name, age);

                // 子类只要初始化新的即可(旧的父类做好了)
                this.stuno = stuno;

                console.log("Student的构造方法");
            }
        }

        // 子类 不重写父类构造方法 之前
        // const s1 = new Student('张三', 20)
        // console.log(s1)

        // 子类 重写父类构造方法 之后
        const s2 = new Student("茂春", 16, "007");
        console.log(s2);

        // 总结
        // 重写作用1: 子类覆盖父类(重新来过), 直接重写即可
        // 重写作用2: 子类扩展父类, 普通扩展(super.被重写方法名(实参): 可以不调用(覆盖效果)), 如果是构造方法重写: 必须先调用父类的构造方法(super(实参)), 一定要先super(),再做别的事情
    </script>
</html>

ES6面对对象 - 元素创建继承

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8" />
        <meta http-equiv="X-UA-Compatible" content="IE=edge" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>ES6面对对象 - 元素创建继承</title>
        <style>
            .element {
                width: 200px;
                height: 200px;
                border-radius: 50%;
                border: 10px solid #00ffff;

                text-align: center;
                font-size: 30px;
                line-height: 200px;

                overflow: hidden;
                float: left;
            }
        </style>
    </head>
    <script src="./js/CreateElement.js"></script>
    <body></body>
    <script>
        // 需求:ES6面向对象, 实现动态创建元素
        const div = new CreateElement("div", "element", "是我想太多");
        div.appendTo("body");

        const span = new CreateElement("span", "element", "你总这么说");
        span.appendTo("body");

        // 放前面
        const p = new CreateElement("p", "element", "想太多");

        p.insertBefore("body", document.querySelector("div"));
    </script>
</html>

ES6面对对象 - 元素创建继承 - 修复缺陷

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8" />
        <meta http-equiv="X-UA-Compatible" content="IE=edge" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>ES6面对对象 - 元素创建继承 - 修复缺陷</title>
        <style>
            .element {
                width: 200px;
                height: 200px;
                border-radius: 50%;
                border: 10px solid #00ffff;

                text-align: center;
                font-size: 30px;
                line-height: 200px;

                overflow: hidden;
                float: left;
            }
        </style>
    </head>
    <script src="./js/CreateElement.js"></script>
    <body></body>
    <script>
        // 需求:ES6面向对象, 实现动态创建元素
        const div = new CreateElement("div", "element", "是我想太多");
        div.appendTo("body");

        const span = new CreateElement("span", "element", "你总这么说");
        span.appendTo("body");

        // 放前面
        const p = new CreateElement("p", "element", "想太多");
        p.insertBefore("body", document.querySelector("div"));

        const img = new CreateImg("images/帅哥.png", "element");
        img.appendTo("body");
    </script>
</html>

js

/**
 * 1. 创建类CreateElement
 * 2. 考虑: 是否有数据需要初始化: 有, 需要根据用户指定的标签,类名和文本, 创建对应的元素: constructor(标签,类名,文本): 数据保存在this中
 * 3. 有什么功能, 就增加什么方法: 一个功能一个方法: appendTo(选择器)
 * */

class CreateElement {
    constructor(tag, className, txt) {
        // 创建元素: 加类 + 加文本
        this.ele = document.createElement(tag);
        this.ele.className = className;
        this.ele.innerHTML = txt;
    }

    appendTo(selector) {
        // 获取父元素
        let parent = document.querySelector(selector);
        // 给父元素添加孩子
        parent.appendChild(this.ele);
    }

    // 放前面
    insertBefore(selector, son) {
        let parent = document.querySelector(selector);
        parent.insertBefore(this.ele, son);
    }
}

// 创建一个图片类:继承CreateElement,修改创建元素的方式(扩展):给元素增加一个src属性

class CreateImg extends CreateElement {
    // 重写构造方法
    constructor(src, className) {
        // 构造方法继承重写:先执行父类的
        super("img", className, "");

        // 标签是写死的 img,类名是用户传入的,文本:单标签,建议使用空字符串

        // 扩展:src属性
        // console.log(this)

        this.ele.src = src;
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Henry_ww

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值