原型、原型链、面向对象制作轮播图

85 阅读4分钟

01_原型

  • 每一个函数都有一个属于自己的原型
  • 作用:我们会在原型内部放一些公共的方法,目的不是为了让构造函数去使用,而是为了让实例化对象去使用
  •   function Person(name) {
                this.name = name
            }
            Person.prototype.sayHi = () => {
                console.log(111)
            }
            const p = new Person('QF666')
            p.sayHi()
    
  • 任何一个数组的构造函数都是 Array
  • 任何一个对象的构造函数都是 Object
  • 任何一个函数的构造函数都是 Function
  • 需求:给数组扩展一个求最大值的方法
  •  Array.prototype.getMax = function () {
                let max = this[0]
                for (let i = 1; i < this.length; i++) {
                    if (max < this[i]) {
                        max = this[i]
                    }
                }
                return max
            }
            const arr1 = new Array(1, 2, 100, 5, 3, 4)
            const max = arr1.getMax()
            console.log(max)
    ​
    ​
            const arr2 = new Array(1, 2, 100, 5, 3, 4, 999)
            const max2 = arr2.getMax()
            console.log(max2)
    

02_万物皆对象

  • JS中,万物都可以称为对象
  • 对象:
  • 含义1:一种数据格式{key:value , key2:value2}
  • 含义2:某一类事务的实例(某一类内容中的真实个体)

03_原型链

  • 查找对象的某一个属性:
  • 先在对象内部开始查找,找到直接使用,然后停止查找
  • 如果没有找到,会找对象的 obj.__ proto __ ,如果找到直接使用,然后停止查找
  • 如果没有找到,会继续去对象的 __ proto__ ,查找,找到直接使用,然后停止查找;如果没有找到,就继续向上查找.....直到找到顶层作用对象 Object.prototype,找到就用,找不到就是 undefined
  •  function Person (name) {
                this.name = name
            }
            Person.prototype.sayHi = function () {
                console.log(100)
            }
            const p = new Person('QF001')
    
  • 问题1:p的__ proto__指向谁?
  • p是Person的实例化对象
  • __ proto__指向自身构造函数的原型
  • p.__ proto __ ===Person.prototype
  •  console.log(p.__proto__ === Person.prototype)-----true
    
  • 问题2:Person的 __ proto __ 指向谁?
  • Person 是构造函数,本质上是函数
  • 只要是一个函数,他就是Function的实例
  • Person. __ proto__指向了他的构造函数的原型,构造函数是Function,那么构造函数的原型Function.prototype
  • Person. __ proto__ ===Function.prototype
  •  console.log(Person.__proto__ === Function.prototype)
    
  • 问题3:Person.prototype的__ proto__指向谁?
  • Person.prototype其实就是构造函数Person的原型对象,本质上就是对象
  • 只要是一个对象,他就是Object的实例
  • Person.prototype.__ proto__ 指向了他的构造函数的原型,构造函数Object,那么构造函数的原型Object.prototype
  • Person.prototype.__ proto__ ===Object.prototype
  •   console.log(Person.prototype.__proto__ === Object.prototype)
    
  • 问题4:Function的__ proto__指向谁?
  • Function是构造函数,本质上就是一个函数
  • 只要是一个函数,他就是Function的实例
  • Function.__ proto__指向了他的构造函数的原型,构造函数Function,那么构造函数的原型Function.prototype
  • Function.__ proto__ ===Function.prototype
  • console.log(Function.__proto__ === Function.prototype)
    
  • 问题5:Function.prototype的__ proto__指向了谁?
  • Function.prototype其实就是构造函数Function的原型对象,本质上是对象
  • 只要是对象,他就是Object的实例
  • Function.prototype.__ proto__指向了他的构造函数的原型,构造函数Object,那么构造函数的原型Object.prototype
  • Function.prototype.__ proto__ ===Object.prototype
  • 问题6:Object的__ proto__指向了谁?
  • Object是一个构造函数,本质上还是一个函数
  • 只要是一个函数,那么他的构造函数就是Function
  • Object.__ proto__指向了他的构造函数的原型,他的构造函数是Function,那么构造函数的原型 Function.prototype
  • Object.__ proto__ === Function.prototype
  •  console.log(Object.__proto__ === Function.prototype)
    
  • 问题7:Object.prototype的__ proto__指向了谁?
  • Object.prototype是构造函数Object的原型对象,本质上就是一个对象
  • Object.prototype是JS顶层的对象
  • Object.prototype.__ proto__ ===null
  • console.log(Object.prototype.__proto__)
    

04_判断数据类型

  • typeof 判断基本数据类型
  •  // 1. typeof
            console.log(typeof('123'))
            console.log(typeof(123))
            console.log(typeof(true))
            console.log(typeof(undefined))
            console.log(typeof([1, 2, 3]))
            console.log(typeof({a:1}))
    
  • constructor可以判断当前数据的构造函数是谁
  • instanceof可以判断左边的构造函数是否等于右边的构造函数
  • 语法:检测的数据 instanceof 狗凹函数
  • 问题:不能判断undefined和null
  •  /**
             *  instanceof
             *      判断左边的构造函数是否等于右边的
            */
            console.log(arr instanceof Array)
            console.log(arr instanceof Function)
            console.log(obj instanceof Array)
            console.log(obj instanceof Object)
    ​
            Array.prototype.constructor = { a: 1 }
            console.log(arr instanceof Array)
    ​
            console.log(undefined instanceof Array)
            console.log(undefined instanceof Object)
            console.log(undefined instanceof Function)
    
  • Object.prototype.toString.call (要判断的数据结构)------推荐使用
  •   // 4. 
            const arr = [1, 2, 3]
            const obj = {
                a: 1,
                b: 2
            }
            /**
             *  Object 这个构造函数的 原型内部 有一个 toString 的方法
             *      这个方法能够帮我们将数据结构转为字符串的形式    '[object 数据结构]'
             * 
             *      我们在使用的时候 如果需要判断其他数据类型, 需要使用 .call这个方法改变内部 this 指向
             * 
             *  这个方法任何数据类型都能准确判断(推荐使用)
            */
            console.log(Object.prototype.toString.call([]))
            console.log(Object.prototype.toString.call(function () { }))
            console.log(Object.prototype.toString.call(undefined))
            console.log(Object.prototype.toString.call(null))
    

05_轮播图(面向对象)

html

<!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>Document</title>
    <style>
        * {
            padding: 0;
            margin: 0;
        }
​
        .banner {
            width: 600px;
            height: 400px;
            border: 5px solid black;
            margin: 200px auto;
            /* overflow: hidden; */
            position: relative;
        }
​
        .banner .img_box {
            width: 500%;
            height: 100%;
            list-style: none;
            display: flex;
            position: absolute;
            left: 0px;
        }
​
        .banner .img_box li {
            width: 600px;
            height: 100%;
            font-size: 50px;
            text-align: center;
            line-height: 400px;
​
            display: none;
        }
​
        .banner .img_box .active {
            display: block;
        }
​
        .banner .focus {
            width: 200px;
            height: 30px;
            background-color: white;
            position: absolute;
            left: 50%;
            transform: translateX(-50%);
            bottom: 30px;
            border-radius: 20px;
            display: flex;
            justify-content: space-evenly;
            align-items: center;
            list-style: none;
        }
​
        .banner .focus li {
            width: 20px;
            height: 20px;
            border-radius: 50%;
            background-color: rosybrown;
            cursor: pointer;
        }
​
        .banner .focus .active {
            background-color: red;
        }
​
        .left,
        .right {
            position: absolute;
            transform: translateY(-50%);
            font-size: 50px;
            color: white;
            top: 50%;
            cursor: pointer;
        }
​
        .left {
            left: 30px;
        }
​
        .right {
            right: 30px;
        }
    </style>
</head><body>
    <div class="banner" id="box1">
        <!-- 放置所有轮播图的盒子 -->
        <ul class="img_box">
            <li class="active" style="background-color: burlywood;">1</li>
            <li style="background-color: royalblue;">2</li>
            <li style="background-color: greenyellow;">3</li>
            <li style="background-color: pink;">4</li>
            <li style="background-color: rgb(201, 255, 192);">5</li>
        </ul>
        <!-- 放置焦点的盒子 -->
        <ol class="focus">
            <!-- <li class="active"></li>
            <li></li>
            <li></li>
            <li></li>
            <li></li> -->
        </ol>
        <!-- 左右按钮 -->
        <div class="left">&lt;</div>
        <div class="right">&gt;</div>
    </div>
​
    <div class="banner" id="box2">
        <!-- 放置所有轮播图的盒子 -->
        <ul class="img_box">
            <li class="active" style="background-color: burlywood;">1</li>
            <li style="background-color: royalblue;">2</li>
            <li style="background-color: greenyellow;">3</li>
            <li style="background-color: pink;">4</li>
            <li style="background-color: turquoise;">5</li>
            <li style="background-color: turquoise;">6</li>
        </ul>
        <!-- 放置焦点的盒子 -->
        <ol class="focus">
            <!-- <li class="active"></li>
            <li></li>
            <li></li>
            <li></li>
            <li></li> -->
        </ol>
        <!-- 左右按钮 -->
        <div class="left">&lt;</div>
        <div class="right">&gt;</div>
    </div>
    <script src="./index.js"></script>
    <script>
        new Banner('#box1', {
            des: 2000
        })
        new Banner('#box2', {
            des: 5000
        })
    </script>
</body></html>

JS

/**
 *  面向对象书写的小技巧
 *
 *          1. 获取元素, 准备变量, 以前是写在全局
 *          面向对象就是把全局变量更改为写到 函数体内部 this.xxx == xxx
 *
 *          2. 书写方法 以前是写在全局
 *          面向对象就是把全局函数, 书写在原型对象内部
 *
 *
 *  面向过程
 *      1. banner
 *      2. imgBox
 *      3. focus
 *      4. index
 *      5. timer
 *    方法
 *      1. 添加假图
 *      2. 调整焦点
 *      3. 自动轮播
 *      4. 点击事件
 *
 *  面向对象
 *      属性:
 *          this.banner = xxx
 *          this.imgBox = xxx
 *          this.focus = xxx
 *          this.index = xxx
 *          this.timer = xxx
 *      方法:
 *          1. 添加焦点
 *          2. 自动轮播
 *          3. 点击事件
 */
class Banner {
    constructor(ele, options) {
        this.banner = document.querySelector(ele);
        this.imgBox = this.banner.querySelector(".img_box");
        this.focus = this.banner.querySelector(".focus");
        this.index = 0; // 记录当前在第个 图片, 默认第一个, 按照下标的形式存储
        this.timer = 0; // 存储定时器ID
​
        this.des = options.des // 存储传递进来的参数
​
        this.setFocus(); // 1. 添加焦点
        this.autoPlay(); // 2. 自动轮播
        this.overOut(); // 3. 鼠标移入移出
        this.clickBan();
    }
    // 原型
​
    // 1. 添加焦点
    setFocus() {
        // 根据图片数量动态生成焦点
​
        // 1. 获取图片数量
        const imgNum = this.imgBox.children.length;
​
        for (let i = 0; i < imgNum; i++) {
            const newLi = document.createElement("li");
​
            newLi.classList.add("new_li_item");
            newLi.dataset.id = i;
​
            if (i == 0) {
                newLi.classList.add("active");
            }
            this.focus.appendChild(newLi);
        }
    }
​
    // 1.5 切换
    cut(type) {
        // 就是给不同的 li 图片 添加类名
​
        // 1. 函数调用时, 先将当前的 li对应的类名去掉
        this.imgBox.children[this.index].classList.remove("active");
        this.focus.children[this.index].classList.remove("active");
​
        /**
         *  使用场景
         *      下一页(自动轮播也属于这种)
         *      上一页
         *      点击焦点, 跳转到对应页
         *
         *  我们约定, type 可以传递三个值
         *      下一页调用时 传递 true
         *      上一页调用时 传递 false
         *      点焦点, 传递对应数字
         */
        // 2. 判断
        if (type === true) {
            // 下一页
            this.index++;
        } else if (type === false) {
            // 上一页
            this.index--;
        } else {
            // 跳转对应页
            this.index = type;
        }
​
        // 3. 边界判断
        if (this.index > this.imgBox.children.length - 1) {
            this.index = 0;
        }
        if (this.index < 0) {
            this.index = this.imgBox.children.length - 1;
        }
​
        // 找到对应的项, 给他添加类名
        this.imgBox.children[this.index].classList.add("active");
        this.focus.children[this.index].classList.add("active");
    }
​
    // 2.自动轮播
    autoPlay() {
        this.timer = setInterval(() => {
            // move 函数
            // 调用一个 类似于 move 功能的函数
            this.cut(true);
        }, this.des);
    }
​
    // 3. 鼠标移入移出事件
    overOut() {
        this.banner.onmouseover = () => {
            // 清除定时器
            clearInterval(this.timer);
        };
        this.banner.onmouseout = () => {
            // 重新打开自动轮播
            this.autoPlay();
        };
    }
    // 4. 点击事件
    clickBan() {
        this.banner.onclick = (e) => {
            if (e.target.className == "right") {
                // 下一页
                this.cut(true);
            }
            if (e.target.className == "left") {
                // 上一页
                this.cut(false);
            }
            if (e.target.className == "new_li_item") {
                // 跳转对应页
                this.cut(e.target.dataset.id - 0);
            }
        };
    }
}
​