JavaScript - 第四周

48 阅读6分钟

day16 + day17

一、animate.css文件

是一个动画库:放着很多很多的动画。
  • 如何使用
1、打开百度:搜索animate.css 得到网址
    http://www.animate.net.cn/
    https://animate.style/
2、下载 - 你们不用做这个操作
3、引入此文件
4、挑选你喜欢的动画,把class放到那个元素上
5、并且要记得设置上animation-duration:3s; 执行时长
6、还需要根据不同的动画,设置不同的初始效果,才会更好看

二、swiper插件

专门的一个轮播插件,提供了你HTML/CSS/JS,我们只需要复制。

三、对象

3.1 面向对象三大特点:封装、继承、多态

3.2 开发方式

1. 面向过程:过程 - 开始->结束
2. 面向对象:对象(属性和方法),js万物皆对象

四、封装/创建/定义自定义对象

  • 直接量方式
var obj={
        "属性名":属性值,
        ...,
        "方法名":function(){操作},//可以简化为箭头函数
        ...
}
  1. 属性名和方法名的""可以不加
  2. 访问对象的属性和方法
    obj.属性名; === obj["属性名"];
    obj.方法名(); === obj"方法名";
  3. js中一切都是对象,除了undefined和null,一切对象的底层都是hash数组
  4. 访问到不存在的属性,返回undefined
  5. 添加新属性和新方法:obj.属性名=新值;obj.方法名=function(){};
  6. 如果我希望遍历出对象所有的东西,必须使用for in,obj[i]才能拿到
  7. 如果你希望在对象的方法里,使用对象自己的属性,写为this.属性名
  8. 构造函数之中this指向当前正在创建的对象
  • 预定义构造函数方式
var obj=new Object();//空对象
//需要自己后续慢慢添加属性和方法
obj.属性名=新值;
obj.方法名=function(){};
  • 自定义构造函数方式:
  1. 创建自定义构造函数
function 类名(name,age,hobby){
        this.name=name;
        this.age=age;
        this.hobby=hobby;
}
//千万不要在里面创建方法,每个对象都会创建出一个相同的方法,浪费内存
  1. 调用构造函数创建对象
var obj=new 类名(实参,...);
  • 面向对象的优点
    1. 所有的属性和方法都保存在一个对象之中 - 更符合现实更有意义
    2. 每个功能特地分开写 - 便于以后维护
    3. 铁锁链舟 - 一个方法触发多个方法联动

五、继承

父对象的成员(属性和方法),子对象可以直接使用
  • 为什么要继承:代码重用!提高代码的复用性,节约了内存空间!提升了网站的性能!
  • 何时继承:只要多个子对象公用的属性和【方法】,都要集中定义在父对象之中
  • 如何找到原型对象(父对象):保存了一类子对象共有属性和共有方法
    1. 对象名.proto; //必须先有一个对象
    2. 构造函数名.prototype;//构造函数名几乎人人都有,除了Math和Window

六、原型链

每个对象都有一个属性:__proto__,可以一层一层的找到每个人的父亲,形成的链式结构,就称之为叫做原型链
  • 可以找到父对象的成员(属性和方法),作用:找共有属性和共有方法
  • 最顶层的是Object的原型、上面放着一个方法toString

七、练习

<!-- 开关门效果 - 封装对象 -->
<button id="btn" style="background-color: #df6215;">···</button>
<div id="box"></div>
<script>
    var door = {
        'btn' : document.querySelector('button'),
        'div' : document.querySelector('div'),
        'init' : function () {//初始化
            this.bind()
        },
        'bind' : function () {
            var me = this//留住this
            this.btn.onclick = function () {
                me.animate(this)
            }
        },
        animate : function (btn) {
            if (btn.style.backgroundColor == 'rgb(223, 98, 21)') {
                btn.style.backgroundColor = '#666'
                this.div.style.display = 'block'
            } else {
                btn.style.backgroundColor = '#df6215'
                this.div.style.display = 'none'
            }
        }
    }
    door.init()
</script>
<!-- 开关门效果 - 面向对象 -->
<section id="sec1">
    <button id="btn" style="background-color: #df6215;">···</button>
    <div id="box"></div>
</section>
<section id="sec2">
    <button id="btn" style="background-color: #df6215;">···</button>
    <div id="box"></div>
</section>
<script>
    function door(parent) {
        this.btn = parent.querySelector('button')
        this.div = parent.querySelector('div')
    }
    door.prototype.init = function () {
        this.bind()
    }
    door.prototype.bind = function () {
        var me = this//留住this
        this.btn.onclick = function () {
            me.animate(this)
        }
    }
    door.prototype.animate = function (btn) {
        if (btn.style.backgroundColor == 'rgb(223, 98, 21)') {
            btn.style.backgroundColor = '#666'
            this.div.style.display = 'block'
        } else {
            btn.style.backgroundColor = '#df6215'
            this.div.style.display = 'none'
        }
    }
    var door1 = new door(sec1)
    door1.init()
    var door2 = new door(sec2)
    door2.init()
</script>
<!-- 选项卡 - 封装对象版 -->
<ul>
    <li class="active" dy="0">家电</li>
    <li dy="1">数码</li>
    <li dy="2">超市</li>
    <li dy="3">建材</li>
    <li dy="4">维修</li>
</ul>
<div class="active">家电</div>
<div>数码</div>
<div>超市</div>
<div>建材</div>
<div>维修</div>
<script>
    var tabs = {
        lis : document.querySelectorAll('li'),
        divs : document.querySelectorAll('div'),
        init : function () {
            this.bind()
        },
        bind : function () {
            this.lis.forEach((li,i) => {
                li.onclick = (e) => {
                    this.animate(e.target,i)
                }
            })
        },
        animate : function (li,i) {
            this.lis.forEach(li => li.className = '')
            this.divs.forEach(div => div.className = '')
            li.className = 'active'
            this.divs[i].className = 'active'
        }
    }
    tabs.init()
</script>
<!-- 选项卡 - 面向对象版 -->
<section id="sec1">
    <ul>
        <li class="active" dy="0">家电</li>
        <li dy="1">数码</li>
        <li dy="2">超市</li>
        <li dy="3">建材</li>
        <li dy="4">维修</li>
    </ul>
    <div class="active">家电</div>
    <div>数码</div>
    <div>超市</div>
    <div>建材</div>
    <div>维修</div>
</section>
<section id="sec2">
    <ul>
        <li class="active" dy="0">家电</li>
        <li dy="1">数码</li>
        <li dy="2">超市</li>
        <li dy="3">建材</li>
        <li dy="4">维修</li>
    </ul>
    <div class="active">家电</div>
    <div>数码</div>
    <div>超市</div>
    <div>建材</div>
    <div>维修</div>
</section>
<script>
    function tabs(parent) {
        this.lis = parent.querySelectorAll('li')
        this.divs = parent.querySelectorAll('div')
    }
    tabs.prototype.init = function () {
        this.bind()
    }
    tabs.prototype.bind = function () {
        this.lis.forEach((li,i) => {
            li.onclick = (e) => {
                this.animate(e.target,i)
            }
        })
    }
    tabs.prototype.animate = function (li,i) {
        this.lis.forEach(li => li.className = '')
        this.divs.forEach(div => div.className = '')
        li.className = 'active'
        this.divs[i].className = 'active'
    }
    var tab1 = new tabs(sec1)
    tab1.init()
    var tab2 = new tabs(sec2)
    tab2.init()
</script>
<!-- 淡出淡入轮播 - 封装对象版 -->
<div class="carousel">
    <div class="img_box">
        <img src="./img/banner1.jpg" alt="" class="active">
        <img src="./img/banner2.jpg" alt="">
        <img src="./img/banner3.jpg" alt="">
    </div>
    <img src="./img/banner3.jpg" alt="">
    <button><</button>
    <button>></button>
    <ul>
        <li class="active"></li>
        <li></li>
        <li></li>
    </ul>
</div>
<script>
    var carousel = {
        div : document.querySelector('.carousel'),
        btns: document.querySelectorAll('button'),
        lis: document.querySelectorAll('li'),
        imgs: document.querySelectorAll('.img_box>img'),
        j: 0,
        timer : null,
        init: function () {
            this.bind()
            this.setInterval()
        },
        bind: function () {
            var me = this
            this.btns.forEach(btn => {
                btn.onclick = function () {
                    if (this.innerText == '>') {
                        me.animate(1)
                    } else {
                        me.animate(-1)
                    }
                }
            })
            this.lis.forEach((li,i) => {
                li.onclick = function () {
                    me.animate(0,i)
                }
            })
            this.div.onmouseover = function () {
                me.clearInterval()
            }
            this.div.onmouseout = function () {
                me.setInterval()
            }
        },
        animate: function (num,i) {
            if (num) {
                this.j += num
                if (this.j == this.imgs.length) {this.j = 0}
                if (this.j == -1) {this.j = this.imgs.length - 1}
            } else {
                this.j = i
            }
            this.clear()
            this.imgs[this.j].className = 'active'
            this.lis[this.j].className = 'active'
        },
        clear : function () {
            this.imgs.forEach(img => img.className = '')
            this.lis.forEach(li => li.className = '')
        },
        setInterval : function () {
            this.timer = setInterval(() => {
                this.animate(1)
            },1000)
        },
        clearInterval : function () {
            clearInterval(this.timer)
        }
    }
    carousel.init()
</script>
<!-- 淡入淡出轮播 - 面向对象版 -->
<div class="carousel1" id="car1">
    <div class="img_box">
        <img src="./img/banner1.jpg" alt="" class="active">
        <img src="./img/banner2.jpg" alt="">
        <img src="./img/banner3.jpg" alt="">
    </div>
    <img src="./img/banner3.jpg" alt="">
    <button><</button>
    <button>></button>
    <ul>
        <li class="active"></li>
        <li></li>
        <li></li>
    </ul>
</div>
<script>
    function carousel(parent) {
        this.div = document.querySelector('.carousel1')
        this.btns = parent.querySelectorAll('button')
        this.lis = parent.querySelectorAll('li')
        this.imgs = parent.querySelectorAll('.img_box>img')
        this.j = 0
        this.timer = null
    }
    carousel.prototype.init = function () {
        this.bind()
        this.setInterval()
    }
    carousel.prototype.bind = function () {
        var me = this
        this.btns.forEach(btn => {
            btn.onclick = function () {
                if (this.innerText == '>') {
                    me.animate(1)
                } else {
                    me.animate(-1)
                }
            }
        })
        this.lis.forEach((li,i) => {
            li.onclick = function () {
                me.animate(0,i)
            }
        })
        this.div.onmouseover = function () {
            me.clearInterval()
        }
        this.div.onmouseout = function () {
            me.setInterval()
        }
    }
    carousel.prototype.animate = function (num,i) {
        if (num) {
            this.j += num
            if (this.j == this.imgs.length) {this.j = 0}
            if (this.j == -1) {this.j = this.imgs.length - 1}
        } else {
            this.j = i
        }
        this.clear()
        this.imgs[this.j].className = 'active'
        this.lis[this.j].className = 'active'
    }
    carousel.prototype.clear = function () {
        this.imgs.forEach(img => img.className = '')
        this.lis.forEach(li => li.className = '')
    }
    carousel.prototype.setInterval = function () {
        this.timer = setInterval(() => {
            this.animate(1)
        },1000)
    }
    carousel.prototype.clearInterval = function () {
        clearInterval(this.timer)
    }
    var carousel1 = new carousel(car1)
    carousel1.init()
</script>
<script>
// 购物车 - 封装对象版
var car = {
    btns : document.querySelectorAll('tbody button'),
    trs : document.querySelectorAll('tbody tr'),
    inint : function () {
        this.getTotal()
        this.bind()
    },
    bind : function () {
        var me = this
        this.btns.forEach(btn => {
            btn.onclick = function () {
                if (this.innerText == '+') {
                    me.animate(this,1)
                } else {
                    me.animate(this,-1)
                }
            }
        })
    },
    animate : function (btn,val) {
        if (val == 1) {
            var num = btn.previousElementSibling
        } else {
            var num = btn.nextElementSibling
        }
        var price = btn.parentNode.previousElementSibling
        var sum = btn.parentNode.nextElementSibling
        var j = parseInt(num.innerText) + val
        if (j > 0) {
            num.innerText = j
        }
        sum.innerText = price.innerText * num.innerText
        this.getTotal()
    },
    getTotal : function () {
        var tot = 0
        this.trs.forEach(tr => {
            tot += parseInt(tr.lastElementChild.innerText)
        })
        total.innerText = tot
    }
}
car.inint()
</script>
<script>
// 购物车 - 面向对象
function car(parent) {
    this.btns = parent.querySelectorAll('tbody button')
    this.trs = parent.querySelectorAll('tbody tr')
}
car.prototype.init = function () {
    this.getTotal()
    this.bind()
}
car.prototype.bind = function () {
    var me = this
    this.btns.forEach(btn => {
        btn.onclick = function () {
            if (this.innerText == '+') {
                me.animate(this,1)
            } else {
                me.animate(this,-1)
            }
        }
    })
}
car.prototype.animate = function (btn,val) {
    if (val == 1) {
        var num = btn.previousElementSibling
    } else {
        var num = btn.nextElementSibling
    }
    var price = btn.parentNode.previousElementSibling
    var sum = btn.parentNode.nextElementSibling
    var j = parseInt(num.innerText) + val
    if (j > 0) {
        num.innerText = j
    }
    sum.innerText = price.innerText * num.innerText
    this.getTotal()
} 
car.prototype.getTotal = function () {
    var tot = 0
    this.trs.forEach(tr => {
        tot += parseInt(tr.lastElementChild.innerText)
    })
    total.innerText = tot
}
var car1 = new car(c1)
car1.init()
</script>

day18

一、面向对象继承笔试题

1.1 判断是自有还是共有

<script>
    // 判断自有还是共有
    var zs = {
        name : '张三',
        age : 18
    }
    zs.__proto__.hobby = '吃饭'
    console.log(zs)
    console.log(zs.hasOwnProperty('name'))//true
    if (zs.hasOwnProperty('hobby')) {
        console.log('自有');
    } else {
        if ('hobby' in zs) {
            console.log('共有')
        } else {
            console.log('没有')
        }
    }
</script>

1.2 删除和修改

  • 自有:
    1. 修改:obj.属性名=新属性值;
    2. 删除:delete obj.属性名;
  • 共有:
    1. 修改:原型对象.属性名=新属性值;
    2. 删除:delete 原型对象.属性名;
<script>
    var zs = {
        name : '张三',
        age : 18
    }
    zs.__proto__.hobby = '吃饭'
    console.log(zs)
    // 修改自有
    zs.age = 20
    console.log(zs)
    // 修改共有
    zs.__proto__.hobby = '睡觉'
    console.log(zs)
    // 删除自有
    delete zs.age
    console.log(zs)
    // 删除共有
    delete zs.__proto__.hobby
    console.log(zs)
</script>

1.3 为老IE的数组添加indexOf方法(如何为一类人创建某个方法)

<script>
    // 为老IE的数组创建indexOf方法
    if (Array.prototype.indexOf === undefined) {//老IE
        Array.prototype.indexOf = function (key,starti) {
            starti === undefined && (starti = 0)
            for (var i = starti; i < this.length; i++) {
                if (this[i] === key) {
                    return i
                }
            }
            return -1
        }
    }
    var arr = [1,2,34,6,8,5,2]
    console.log(arr.indexOf(2))//1
    console.log(arr.indexOf(2,2))//6
    console.log(arr.indexOf(3))//-1
</script>
<script>
    // 为老IE的字符串创建trim方法
   if (String.prototype.trim === undefined) {//老IE
        String.prototype.trim = function () {
            return this.replace(/^\s+|\s+$/g,'')
        }
   }
   var str = '   wo   '
   console.log(str.trim());//wo
</script>
<script>
    //为数组添加一个求和的方法,以及添加一个求平均值的方法
    Array.prototype.add = function () {
        for(var i = 0,sum = 0; i < this.length; i++) {
            sum += this[i]
        }
        return sum
    }
    Array.prototype.avg = function () {
        return this.add()/this.length
    }
    var arr1 = [1,2,3,4,5]
    var arr2 = [6,7,8,9,10]
    console.log(arr1.add());//15
    console.log(arr2.add());//40
    console.log(arr1.avg());//3
    console.log(arr2.avg());//8
</script>

1.4 如何判断x是不是一个数组

不能用typeof(),typeof()只能检查原始类型,不能检查引用类型,如果检查引用类型得到的结果都是一个object。

<script>
    // 判断x是不是数组
    var obj={"name":"啦啦啦"}
    var arr=[1,2,3,4]
    var now=new Date()
    var reg=/\s/
    // 1、判断x是否继承自Array.prototype
    console.log(Array.prototype.isPrototypeOf(obj))//false
    console.log(Array.prototype.isPrototypeOf(arr))//true
    console.log(Array.prototype.isPrototypeOf(now))//false
    console.log(Array.prototype.isPrototypeOf(reg))//false
    // 2、判断是不是由Array这个构造函数创建的
    console.log(obj instanceof Array)//false
    console.log(arr instanceof Array)//true
    console.log(now instanceof Array)//false
    console.log(reg instanceof Array)//false
    // 3、Array.isArray(x); - ES5新增的方法,只有数组可以这么使用
    console.log(Array.isArray(obj))//false
    console.log(Array.isArray(arr))//true
    console.log(Array.isArray(now))//false
    console.log(Array.isArray(reg))//false
    // 4、输出【对象的字符串】形式
    console.log(Object.prototype.toString.call(obj) === '[object Array]')//false
    console.log(Object.prototype.toString.call(arr) === '[object Array]')//true
    console.log(Object.prototype.toString.call(now) === '[object Array]')//false
    console.log(Object.prototype.toString.call(reg) === '[object Array]')//false
</script>

1.5 实现自定义继承:

<script>
    // 自定义继承
    var zs = {
        "phone": "威图",
        "dog": "阿拉斯加",
        "gf": "很多",
    }
    var zh = {
        "money":10000000
    }
    zs.__proto__ = zh
    console.log(zs);
    console.log(zh);
    console.log(zs.money);
</script>
<script>
    // 批量设置继承
    function h5(name,age,hobby) {
        this.name = name
        this.age = age
        this.hobby = hobby
    }
    var pg = {
        js : 200
    }
    h5.prototype = pg
    var zs = new h5('张三',18,'吃饭')
    console.log(zs)
</script>

二、class关键字

简化面向对象(封装、继承、多态)
<script>
    class lizi {
        constructor(price,weight) {
            // 里面放的都是自有属性
            this.price = price
            this.weight = weight
        }
        // 共有方法
        total() {
            return `提子的总价为:` + this.price * this.weight
        }
    }
    class fruit extends lizi {
        //extends的作用:1、继承自的自有属性全部都不用再写,只需要写一次super(),2、自动继承到共有方法
        constructor(price,weight,kind) {
            super(price,weight)
            this.kind = kind
        }
        total() {
            return `${this.kind}的总价为:` + this.price * this.weight
        }
    }
    var ti = new lizi(11,5)
    console.log(ti)
    console.log(ti.total());

    var fru = new fruit(8,4,'苹果')
    console.log(fru)
    console.log(fru.total())
</script>

三、闭包

3.1 作用域:

  • 全局:随处可用,可以反复使用,缺点:容易被污染
  • 函数:只能在函数调用时内部可用,不会被污染,缺点:一次性的,是会自动释放的

3.2 函数的执行原理:

  1. 程序加载时:
    • 创建执行环境栈(ECS):保存函数调用顺序的数组
    • 首先压入全局执行环境(全局EC)
    • 全局EC引用着全局对象window
    • window中保存着我们全局变量
  2. 定义函数时:
    • 创建函数对象:封装代码段
    • 在函数对象中有一个scope(作用域)属性:记录着函数来自的作用域是哪里
    • 全局函数的scope都是window
  3. 调用前:
    • 在执行环境栈(ECS)压入新的EC(函数的EC)
    • 创建出活动对象(AO):保存着本次函数调用时用到的全局变量
    • 在函数的EC中有一个scope chain(作用域链)属性引用着AO
    • AO有一个parent属性是函数的scope引用着的对象
  4. 调用时:
    • 正是因为有前面三步,才来带变量的使用规则:优先使用自己的,自己没有找全局,全局没有就报错
  5. 调用完:
    • 函数的EC会出栈,没人引用AO,AO自动释放,局部变量也就释放了

3.3 闭包:

希望保护一个可以【反复使用的局部变量】的一种词法结构,其实还是一个函数,只是写法比较特殊

  • 何时使用:希望保护一个可以【反复使用的局部变量】的时候
  • 如何使用:
    1. 两个函数进行嵌套
    2. 外层函数创建出受保护的变量
    3. 外层函数return出内层函数
    4. 内层函数再操作受保护的变量
  • 判断是不是闭包:有没有两个函数嵌套,返回了内层函数,内层函数再操作受保护的变量
  • 外层函数调用了几次,就创建了几个闭包,受保护的变量就有了几个副本
  • 同一次外层函数调用,返回的内层函数,都是在操作同一个受保护的变量
  • 缺点:受保护的变量,永远都不会被释放,使用过多,会导致内存泄漏
<script>
    function factory() {
        var i = 0
        return function () {
            i ++
            return i
        }
    }
    var icbc = factory()
    console.log(icbc())//1
    console.log(icbc())//2
    console.log(icbc())//3
    var abc = factory()
    console.log(abc())//1
</script>

四、防抖节流

  • elem.onmousemove - 鼠标移动事件
<script>
    div.onmousemove = function () {
        inner()
    }
    function fdjl() {
        var timer = null
        return function() {
            if (timer !== null) {
                clearTimeout(timer)
                timer = null
            }
            timer = setTimeout( ()=> {
                div.innerHTML ++
            },1000)
        }
    }
    var inner = fdjl()
</script>
  • input.oninput - 每次输入/改变都会触发
<script>
    inp.oninput = function () {
        inner()
    }
    function fdjl() {
        var timer = null
        return function () {
            if (timer !== null) {
                clearTimeout(timer)
                timer = null
            }
            timer = setTimeout( () => {
                console.log(inp.value)
            },1000)
        }
    }
    var inner = fdjl()
</script>
  • onresize - 每次窗口改变大小都会触发
<script>
    window.onresize = function () {
        inner()
    }
    function fdjl() {
        var timer = null
        return function() {
            if (timer !== null) {
                clearTimeout(timer)
                timer = null
            }
            timer = setTimeout( ()=> {
                if (innerWidth > 1280) {
                    div.style.backgroundColor = '#666'
                } else if (innerWidth > 648) {
                    div.style.backgroundColor = '#fc1'
                } else {
                    div.style.backgroundColor = 'skyblue'
                }
            },1000)
        }
    }
    var inner = fdjl()
</script>

五、两链一包

5.1 作用域链

以函数的EC的scope chain属性为起点,经过AO,逐级引用,形成的一条链式结构,我们就称之为叫做作用域链

  • 作用:查找变量,带来了变量的使用规则:优先使用自己的,自己没有找全局,全局没有就报错

5.2 原型链

每个对象都有一个属性叫做.proto,可以一层一层的找到每个对象的原型对象,最顶层的就是Object的原型,形成的一条链式结构,我们就称之为叫做原型链

  • 作用:查找属性和方法

5.3 闭包

希望保护一个可以【反复使用的局部变量】的一种词法结构

  • 作用:专门用于防抖节流