JS高级
箭头函数
与JS基础 函数一致,用法更加简洁高级
<script>
// JS基础中 函数写法
function func1(num1) {
return num1 + 100
}
// JS高级中 使用箭头函数
const func2 = (num1) => num1 + 100
// 没有形参 没有返回值 2行代码
const func3 = () => {
console.log(`执行1`);
console.log(`执行2`);
}
// 没有形参 没有返回值 1行代码 大括号都可以省略
const func4 = () => console.log(`执行1`);
// 一个形参 没有返回值 1行代码
// const func5 = (num1) => console.log(num + 1);
const func5 = num1 => console.log(num + 1);
// 两个以上形参(括号不能省略) 没有返回值 1行代码
const func6 = (num1,num2) => console.log(num1+num2);
// 没有形参 有返回值 2行代码
const func7 = () => {
let num = 100
return num + 100
}
// 没有形参 有返回值 1行代码
const func8 = () => {
return 100 + 200
}
// 没有形参 有返回值 1行代码 等价上述写法
const func9 = () => 100 + 200
let btn = document.querySelector(`button`)
btn.addEventListener(`click`,()=>{
console.log(123);
})
</script>
数组常见方法
一、forEach
1.数组每个元素都执行一次回调函数 与JS基础中for循环类型
2.for循环可以通过break打断 forEach不可以通过break打断
3.forEach 是高阶函数
<script>
const arr = [`a`,`b`,`c`]
// for循环 可以break打断 forEach不能通过break打断
arr.forEach((value,index)=>{
console.log(`值 是${value} 下标 是${index}`);
})
// 相同 写法
arr.forEach((value,index)=>console.log(`值 是${value} 下标 是${index}`))
// 一个形参时
arr.forEach(value=>console.log(`值 是${value}`))
</script>
二、map
根据原来的数组返回新的数组(循环数组,在循环的回调函数中返回数据,组装成新的数组)
<script>
const arr1 = [`a`,`b`,`c`] //组装新数组 添加`我的字母是`
const newArr1 = arr1.map((value)=>`我的字母是`+value)
console.log(newArr1);
const arr2 = [10,11,12] //组装新数组 [11,12,13]
const newArr2 = arr2.map(value=>value+1)
console.log(newArr2);
const arr3 = [{name:`悟空`},{name:`八戒`}] //组装新数组 添加color:`red`
const newArr3 = arr3.map((value)=>{
value.color = `red`
return value
})
console.log(newArr3);
const arr = [`刘德华`,`郭德纲`,`林志颖`] //组装新数组 添加DIV标签渲染页面
const newArr = arr.map((value)=>`<div>${value}</div>`)
const html = newArr.join(``)
document.body.innerHTML=html
// 究极写法
let renderHTML = value=>`<div>${value}</div>`
document.body.innerHTML=[`刘德华`,`郭德纲`,`林志颖`].map(renderHTML).join(``)
</script>
捐赠管理系统-map渲染
<script>
function render() {
// 只能使用 map方法 和 数组转方式方法 join 来实现 拼接html的功能
// 把 arr 转成(map、join 来实现功能) 变量 html 让下面的代码 (tbody.innerHTML = html;) 执行成功
let newArr = arr.map((value) =>{
return `<tr>
<td>${value.id}</td>
<td>${value.person}</td>
<td>${value.unit}</td>
<td>${value.money}</td>
<td>${value.date}</td>
<td>
<a href="#" class="del">删</a>
<a href="#" class="update">改</a>
</td>
</tr>`
})
let html = newArr.join(``)
tbody.innerHTML = html;
}
// 根据数组数组渲染页面
render();
</script>
运用map返回数组对象
<script>
let arr = [`a`,`b`,`c`] //返回三个对象 name:`a`...
let newArr = arr.map((value)=>{
return {name:value}
}) // 写法1
let newArr2 = arr.map((value)=>({name:value}))
console.log(newArr2); // 写法2
console.log(newArr);
const func = (num) => {a:123} //返回undefined JS不知道你是块级空间还是对象
const func1 = (num1) => {
return {a:123}
} //返回对象 这个时候就明确了
const func2 = (num2) => ({a:123}) //返回对象 加小括号表示 返回里面数据 也就是return {a:1}
console.log(func2);
</script>
大括号表示两种含义:对象 或 块级空间:
区别点
总结
三、every
判断如果数组中每一个元素是否符合条件 返回true和false
<script>
let arr = [1,3,4] // 判断数组每个元素是否都大于5
let result = arr.every((value) => {
if(value>5){
return true
}else{
return false
}
})
console.log(result);
let arr2 = [true,false,true,true] //只要有一个false 返回false
let result2 = arr2.every((value) => {
if(value===true){
return true
}else{
return false
}
})
console.log(result2);
// 如果是空数组 调用every 直接返回true
let arr1 = []
let result1 = arr1.every((value)=>console.log(`我是真的`))
console.log(result1);
</script>
使用场景:全选框和复选框案例
<script>
// 给每一个商品绑定点击事件
for (let index = 0; index < checkboxList.length; index++) {
checkboxList[index].addEventListener('click', function () {
// 判断是否达到了全选 条件
// 判断每一个小小的复选框的选中状态 如果都是true,那么就全选
// let checked = checkboxList.every((value)=>{
// if(value.checked===true){
// return true
// }else {
// return false
// }
// })
let checked = checkboxList.every((value)=>value.checked)
// 设置全选按钮即可
checkAll.checked = checked;
});
</script>
细节:因为获取的是伪数组,需要转换为数组 才可以使用every方法
<script>
let checkboxList = document.querySelectorAll('.ck');
// checkboxList 现在是一个伪数组
checkboxList=[...checkboxList];// OK 不能用concat 提取还是伪数组
let li = document.querySelectorAll(`li`) //伪数组
// 之前使用转数组方式太LOW
// 第一种
let liArr = [].concat(li)
console.log(liArr); // 弊端 嵌套了
// liArr = [li伪数组] => liArr[0] = li伪数组 还是不能使用every方法
// 第二种
let liArr2 = [...li]
console.log(liArr2);
</script>
踩坑点:
四、some
检测数组中只要有一个符合条件就返回true(与every类似)
五、filter
过滤满足条件的数据,组装新数组
<script>
let arr = [1,2,3,4,5,6,7] // 返回奇数
let newArr = arr.filter((value)=>{
if(value%2!==0){
return true
}else{
return false
}
})
console.log(newArr);
</script>
使用场景:代办列表计算需求
<script>
unfinish.innerText=`${arr.filter((value)=>!value.checked).length}项未完成`
finish.innerText=arr.filter((value)=>value.checked).length
</script>
面向对象
一、面向对象思维
是一种行业通用 写项目级代码的思维,引导我们编写高质量代码
万物皆对象,特点是封装和继承
对象在内存中示意图
细节:对象在栈中创建的是一个地址,然后指向堆中的数据
二、创建对象方法
1.字面量
<script>
let obj1 = {username:`悟空`,height:`180`}
let name1 = 123
let obj2 = {username:`悟空`,height:`180`}
let name2 = 123
let obj3 = {username:`悟空`,height:`180`}
let name3 = 123
let obj4 = {username:`悟空`,height:`180`}
let name4 = 123
// 字面量对象 也就是字面看到的 这样使用不方便维护和维修
// 例如 当数据量大 想要修改name属性 为username =>使用工厂函数
</script>
2.工厂函数
缺点:失去血缘关系,无法简单分辨对象的特征。后期无法实现继承
<script>
// 方便维护 这个时候想要更换name为username,直接改
function createPerson(name,age,height) {
return {
// name : name,
username:name,
age:age,
height:height
}
}
let obj1 = createPerson(`黄某`,22,180)
let obj2 = createPerson(`黄某2`,22,180)
let obj3 = createPerson(`黄某3`,22,180)
console.log(obj1);
console.log(obj2);
console.log(obj3);
// 弊端:无法实现 继承的作用 例如儿子无法继承父亲的
</script>
3.构造函数
<script>
// 声明一个函数 首字母大写 行内规范
function CreatePerson(name,age,height) {
//固定写法 给this赋值
this.name=name,
this.age=age,
this.height=height
this.color = `red` // 固定就写死,不用给变量了
}
// 通过 new的方式 创建对象
const obj1 = new CreatePerson(`悟空`,100,180)
const obj2 = new CreatePerson(`八戒`,100,160)
console.log(obj1);
console.log(obj2);
</script>
构造函数的弊端,同一个say方法占据两份内存
<script>
function CreatePerson(name) {
this.name=name,
this.say=function(){
console.log(`我是一个say方法`);
}
}
const obj1 = new CreatePerson(`悟空`)
const obj2 = new CreatePerson(`八戒`)
//当我判断两个obj的say方法, 返回false 原因:两个say是不相同的内存空间
console.log(obj1.say===obj2.say);
</script>
解决方法:提取用一个say方法
<script>
function say(){
console.log(`我是公用的方法`);
}
function CreatePerson(name) {
this.name = name,
this.say = say
}
const obj1 = new CreatePerson(`悟空`)
const obj2 = new CreatePerson(`八戒`)
console.log(obj1.say===obj2.say);
</script>
构造函数性能问题总结
1.基本类型和引用类型"="的不同
2.缺点:会导致全局变量的污染,很容易导致覆盖 不够优雅
3.优点:方便代码维护,也解决了性能的问题
原型(对象)模式(解决全局污染问题)
1.原型对象是JS自动帮我们添加的,是很合构造对象存在的一个对象
2.把构造函数看成人 原型对象就是人的DNA,修改DNA 构造函数的实例也会发生改变
3.原型上一般式挂载函数
<script>
function CreatePerson(name) {
this.name=name
}
// 解决了 全局污染的问题 也解决了性能的问题 最常用方式
CreatePerson.prototype.say = function(){
console.log(`你好`);
}
const obj1 = new CreatePerson(`悟空`)
const obj2 = new CreatePerson(`八戒`)
function CreatStudents() {}
// 无全局污染问题
CDATASection.prototype.say = function(){
console.log(`学生们好`);
}
</script>
总结:构造函数内只放属性,原型对象里都是放方法 (记忆)
三、面向对象-初体验
补充知识
<script>
// 创建不同人 都有自己名字 共同一个行为 say 打印自己名字
function Cperson(name) {
this.name = name
}
Cperson.prototype.say = function(){
// this 指向了实例 通过this 实现了 数据传递 = 访问了构造函数的数据
console.log(this.name);
}
let obj1 = new Cperson(`八戒`)
let obj2 = new Cperson(`悟空`)
obj1.say()
obj2.say()
</script>
案例
<script>
// 需求: 通过new Myimg(`图片地址`),页面会出现一张图片 然后点击按钮 放大缩小
function Myimg(src) {
let img = document.createElement(`img`)
img.src = src
document.body.appendChild(img)
this.dom=img
}
Myimg.prototype.scale = function () {
this.dom.classList.add(`scale`)
}
let img1 = new Myimg(`./9.5/01.jpg`)
let btn = document.querySelector(`button`)
btn.addEventListener(`click`,function(){
img1.scale()
})
</script>
<script>
function Div(text) {
let div = document.createElement(`div`)
div.innerText = text
document.body.appendChild(div)
this.dom = div
}
Div.prototype.changeColor = function(color){
this.dom.style.backgroundColor=color
}
Div.prototype.setFont = function(font){
this.dom.style.fontSize=font
}
let img1 = new Div(`这是一个DIV`)
let btn = document.querySelector(`button`)
btn.addEventListener(`click`,function(){
img1.changeColor(`red`)
img1.setFont(`100px`)
})
</script>