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(){操作},//可以简化为箭头函数
...
}
- 属性名和方法名的""可以不加
- 访问对象的属性和方法:
obj.属性名; === obj["属性名"];
obj.方法名(); === obj"方法名"; - js中一切都是对象,除了undefined和null,一切对象的底层都是hash数组
- 访问到不存在的属性,返回undefined
- 添加新属性和新方法:obj.属性名=新值;obj.方法名=function(){};
- 如果我希望遍历出对象所有的东西,必须使用for in,obj[i]才能拿到
- 如果你希望在对象的方法里,使用对象自己的属性,写为this.属性名
- 构造函数之中this指向当前正在创建的对象
- 预定义构造函数方式:
var obj=new Object();//空对象
//需要自己后续慢慢添加属性和方法
obj.属性名=新值;
obj.方法名=function(){};
- 自定义构造函数方式:
- 创建自定义构造函数
function 类名(name,age,hobby){
this.name=name;
this.age=age;
this.hobby=hobby;
}
//千万不要在里面创建方法,每个对象都会创建出一个相同的方法,浪费内存
- 调用构造函数创建对象
var obj=new 类名(实参,...);
- 面向对象的优点:
- 所有的属性和方法都保存在一个对象之中 - 更符合现实更有意义
- 每个功能特地分开写 - 便于以后维护
- 铁锁链舟 - 一个方法触发多个方法联动
五、继承
父对象的成员(属性和方法),子对象可以直接使用
- 为什么要继承:代码重用!提高代码的复用性,节约了内存空间!提升了网站的性能!
- 何时继承:只要多个子对象公用的属性和【方法】,都要集中定义在父对象之中
- 如何找到原型对象(父对象):保存了一类子对象共有属性和共有方法
- 对象名.proto; //必须先有一个对象
- 构造函数名.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 删除和修改
- 自有:
- 修改:obj.属性名=新属性值;
- 删除:delete obj.属性名;
- 共有:
- 修改:原型对象.属性名=新属性值;
- 删除: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 函数的执行原理:
- 程序加载时:
- 创建执行环境栈(ECS):保存函数调用顺序的数组
- 首先压入全局执行环境(全局EC)
- 全局EC引用着全局对象window
- window中保存着我们全局变量
- 定义函数时:
- 创建函数对象:封装代码段
- 在函数对象中有一个scope(作用域)属性:记录着函数来自的作用域是哪里
- 全局函数的scope都是window
- 调用前:
- 在执行环境栈(ECS)压入新的EC(函数的EC)
- 创建出活动对象(AO):保存着本次函数调用时用到的全局变量
- 在函数的EC中有一个scope chain(作用域链)属性引用着AO
- AO有一个parent属性是函数的scope引用着的对象
- 调用时:
- 正是因为有前面三步,才来带变量的使用规则:优先使用自己的,自己没有找全局,全局没有就报错
- 调用完:
- 函数的EC会出栈,没人引用AO,AO自动释放,局部变量也就释放了
3.3 闭包:
希望保护一个可以【反复使用的局部变量】的一种词法结构,其实还是一个函数,只是写法比较特殊
- 何时使用:希望保护一个可以【反复使用的局部变量】的时候
- 如何使用:
- 两个函数进行嵌套
- 外层函数创建出受保护的变量
- 外层函数return出内层函数
- 内层函数再操作受保护的变量
- 判断是不是闭包:有没有两个函数嵌套,返回了内层函数,内层函数再操作受保护的变量
- 外层函数调用了几次,就创建了几个闭包,受保护的变量就有了几个副本
- 同一次外层函数调用,返回的内层函数,都是在操作同一个受保护的变量
- 缺点:受保护的变量,永远都不会被释放,使用过多,会导致内存泄漏
<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 闭包
希望保护一个可以【反复使用的局部变量】的一种词法结构
- 作用:专门用于防抖节流