JavaScript高级(一)
一、箭头函数
1.对比函数
// 以前写函数
function func1(num1) {
return num1 + 100;
}
// 箭头函数的时候
// const func2 = (num1) => num1 + 100;
// 定义一个箭头函数 没有形参 没有返回值
const func2 = () => {
console.log("执行业务1");
console.log("执行业务2");
};
2.没有形参、没有返回值、业务只有一行代码 大括号都可以省略
const func3 = () => console.log("执行业务1");
3.只有一个形参、没有返回值、业务只有一行代码
const func4 = num => console.log(num + 1);
const func4 = (num) => console.log(num + 1);
4.两个或者多个参数(括号不能省略)、没有返回值、业务只有一行代码
const func5 = (a, b) => console.log(a + b);
5.没有形参,有返回值 业务两行代码
const func6 = () => {
let a = 100;
return a + 100;
};
6.没有形参、有返回值,业务一行代码
const func7 = () => 100 + 200; // 相等于 return 100+200
console.log(func7());
const button = document.querySelector("button");
button.addEventListener("click", () => {
console.log(123321);
});
7.箭头函数-返回对象
(1)箭头函数 会认为 这个大括号 是 块级空间 符号 而不是对象的符号
const newArr1 = arr.map((value) => { name: value; }); // 这个大括号 是表示 对象的符号 还是表示 可以块级空间
// const newArr2=arr.map(value=> {
// console.log(123) ;
// console.log(123) ;
// console.log(123) ;
// return undefined
// } );
// // js认为 大括号是 块级空间 可以写js语句
// {
// console.log(123);
// console.log(123);
// console.log(123);
// }
// let obj={ // js会认为大括号是 对象的符号 里面不能写 语句
// console.log(123);
// console.log(123);
// console.log(123);
// }
(2)const arr = ["a", "b", "c"];返回 [ {name:"a",name:"b",name:"c"} ],思路
const arr = ["a", "b", "c"];
// 返回 [ {name:"a",name:"b",name:"c"} ]
// const newArr=arr.map(value=>name:value );// 排除!
// const newArr=arr.map(value=>{name:value} ); // 思路正确 代码不正确
// const newArr=arr.map(value=>{
// name:value
// } ); // 思路正确 代码不正确
// const newArr=arr.map(value=>{
// name:value
// return undefined
// } ); // 思路正确 代码不正确
// const newArr=arr.map(value=>{
// console.log(1);
// console.log(2);
// } ); // 思路正确 代码不正确
// console.log(newArr);
(3)箭头函数 的返回值 可以被省略
const func = (num) => num + 1; // 相当于 return num+1
const func1 = (num) => {
return num + 1;
}; // 这个大括号表示 块级空间
const func2 = (num) => {
num + 1;
}; // 会执行 num+1 但是没有返回值
const func3 = (num) => {
let num1 = num + 1;
let num2 = num1 + 2;
};
// console.log(func3());
const func4 = (num) => {
return { a: 123 };
};
// console.log(func4());
const func5 = (num) => {}; // 只要直接出现 大括号 就表示 块级空间 和它里面写什么代码没有关系
// console.log(func5());
const func6 = (num) => {
a: 2;
}; // 这个大括号就是对象(你的认为!! 浏览器还是一样 大括号就是块级空间)
// console.log(func6());
// 如果你真的看不懂 没有办法, 你先不要优雅!! 先用以前的function
(4)如果你一定要在箭头函数中想要通过省略 return的方式来 返回对象,请你加上一个小括号
const func7 = (num) => ({ a: 123 }); // => 右边加了小括号 表示想要返回 小括号里面的数据 return {a:123};
const func8 = (num) => {
a: 123;
}; // => undefined
console.log(func7());
{
a: 123;
} console.log(func8()); // undefined
二、数组常见方法
1.常用数组方法
2.forEach():数组每一个元素都执行一次回调函数(for循环可以通过 break来打断、 forEach不能通过break打断)
const arr = ["a", "b", "c"];
// 分别打印他们
arr.forEach(function (value, index) {
console.log(`值 是 ${value} 下标是 ${index}`);
});
// 箭头函数写法
arr.forEach((value, index) =>console.log(`值 是 ${value} 下标是 ${index}`));
arr.forEach((value) => console.log(`值 是 ${value}`));
3.map():通过制定的函数处理数组的每一个元素,并返回处理后的数组
(1)案例
<script>
const texts = ["刘德华", "郭德纲", "林志颖"];
// 返回 [<div>刘德华</div>,<div>郭德纲</div>,<div>林志颖</div>]
const newTexts = texts.map((value) => `<div>${value}</div>`);
// console.log(newTexts)
// 转化字符串
const html = newTexts.join("");
document.body.innerHTML = html;
</script>
(2)案例-捐赠管理系统-渲染部分
<script>
// 获取tbody
const tbody = document.querySelector("tbody");
// 定义数据
const arr = [
// id:数据编号 person:捐赠人姓名 unit:捐赠单位名称 money:捐赠金额 date:捐赠日期
{
id: 1,
person: "刘德化",
unit: "壹基金",
money: 1000,
date: "2021-10-5",
},
{
id: 2,
person: "周杰伦",
unit: "自然之友",
money: 1000,
date: "2021-01-15",
},
{
id: 3,
person: "李连杰",
unit: "嫣然基金",
money: 1000,
date: "2021-06-7",
},
];
// 根据数组来渲染页面
function render() {
const newArr = arr.map(
(value) => `
<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>
`
);
// 只能使用 map方法 和 数组转方式方法 join 来实现 拼接html的功能
// 把 arr 转成(map、join 来实现功能) 变量 html 让下面的代码 (tbody.innerHTML = html;) 执行成功
const html = newArr.join("");
tbody.innerHTML = html;
}
// 根据数组数组渲染页面
render();
</script>
4.every():检测数值元素的每一个元素是否都符合条件
(1)案例-全选与不全选
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;
});
}
5.伪数组转真数组
<body>
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
</ul>
<script>
const lis = document.querySelectorAll("li"); // 伪数组
// const liList=domToArr(lis);
// console.log(liList.every);
// 转成真正的数组 一堆方式
// const liList = [].concat(lis);
// liList = [ lis伪数组 ]
// liList[0] = lis伪数组
// liList[0].every === lis.every 伪数组调用every
// console.log(liList[0].every);
// 伪数组一堆转数组的代码
// 有很多后两天才讲到的
// 现在先简单用一个
// const liList=[...伪数组]
const liList = [...lis]; // 最简单的转伪数组的方式 先这么用
</script>
</body>
6.some():检测数组元素中是否有元素符合指定条件
some()
function some() {
// 检测数组,其中只要有一个元素符合条件,some返回true (every要求每一个都符合)
const arr = [1, 3, 4, 6, 2];
// 这个数组里面有没有元素大于6的
const result = arr.some((value) => value > 6);
console.log(result);
7.filter():检测数值元素,并返回符合条件所有元素的数组
(1)案例
filter();
function filter() {
// 过滤, 过滤出满足条件的数据 =>新的数组
const arr = [1, 2, 3, 4, 5, 6, 7];
// 返回 奇数
// const newArr = arr.filter((value) => {
// // 如果你return 了 true 表示当前的value你想要
// if (value % 2 !== 0) {
// // value 1 2 3 4 5 6
// // value%2!==0 value=[1,3,5,7]
// // 奇数
// return true;
// } else {
// return false;
// }
// });
const newArr = arr.filter((value) => value % 2 !== 0);
console.log(newArr);
}
(2)案例-待办列表
// 适用下方计算复选框框选时,未完成和完成的数量案例
function statistics() {
// 未完成
unFinishSpan.innerText =
arr.filter((value) => !value.checked).length + " 未完成";// 未选中状态的个数
// 已经完成
finishA.innerText = arr.filter((value) => value.checked).length;// 选中状态的个数
}
三、面向对象
1.什么是面向对象
一种编程行业通用的写项目级的代码的思维,引导我们如何编写高质量的代码,万物皆对象 - 看待事物的角度,(属性:数据,行为:动作(方法))。代码特点是封装和继承
2.字面量-创建对象
(1)特点:简单粗暴、不适合创建多个同样类型的对象的场景
(2)案例
const obj ={ name:"悟空",height:100,age:5000};
<script>
const obj1 = { username: "悟空1", tel: 123321 };
const name1 = 123;
const obj2 = { username: "悟空2", tel: 123322 };
const name2 = 123;
const obj3 = { username: "悟空3", tel: 123323 };
const name3 = 123;
const obj4 = { username: "悟空4", tel: 123324 };
const name4 = 123;
const obj5 = { name: "悟空5", tel: 123325 };
// 好处 方便
// 不方便维护-修改
// 不想要name属性,修改 username
</script>
3.工厂函数
(1)特点:容易理解 、失去血缘关系,无法简单分辨对象的特征 、后期无法实现继承
(2)案例
<script>
function createPerson(name, age, height) {
return {
// name: name,
username: name,
age: age,
height: height,
};
}
// 创建对象
const obj1 = createPerson("悟空", 18, 150);
const obj2 = createPerson("八戒", 20, 140);
const obj3 = createPerson("龙马", 30, 190);
console.log(obj1);
console.log(obj2);
console.log(obj3);
// 优点 容易维护
// name => username
// 弊端 无法实现 继承的作用!
</script>
4.构造函数
(1)特点:可以方便的创建对象、可继承、还有后续更多的优势
(2)案例
<script>
// 专业术语
// 会把 createPerson 叫做 构造函数
// 会把 createPerson 创建出来的对象 叫做 实例
// 1 声明一个函数
function createPerson(name, age) {
// 2 给this赋值
this.name = name;
this.age = age;
// this.color="red";
}
// 2 通过new的方式来创建对象
const obj1 = new createPerson("悟空", 10);
console.log(obj1);
console.log(obj1.name);
console.log(obj1.age);
</script>
5.构造函数-性能问题(1)
(1)弊端:同一个 say 方法占据了两份内存
function createStudent(name, age) {
this.name = name;
this.age = age;
this.say = function () {
console.log(this.name);
}
}
const obj = new createStudent("悟能", 83);
const obj1 = new createStudent("悟能1", 84);
console.log(obj.say === obj1.say); // false 不是同一say方法 浪费了内存
(2)案例-举例理解
<script>
function say() {
console.log("这个是say方法");
}
// 构造函数的首字母大写 - 行内编码规范
function CreatePerson(name) {
this.name = name; // 创建了name属性
// this.say = function () {
// console.log('这个是say方法');
// };
this.say = say; // say函数引用类型, 构造函数中的say 其实和外面的say内存地址一致的 同一个say方法
}
const obj1 = new CreatePerson("悟空");
const obj2 = new CreatePerson("八戒");
// obj1.say();
// obj2.say();
// 两个say的判断比较 是false 说明 两个say是在不同的内存空间上
// 两个say 占用了两个内存空间
// console.log(obj1.say === obj2.say); // false
console.log(obj1.say === obj2.say); // true
// 对于基本类型来说,= 就是复制了一份值
// let num = 100;
// let num2 = num; // 复制值 num和 num2占两给内存 各自不影响
// num2 = 1000;
// console.log(num);
// 对于引用类似 = 其实把地址拷贝了一份给新的对象 两个数据 公用一份数据
// let person1 = { name: '悟空' }; // person1 指向了 一个地址 0x1111 存放悟空
// let person2 = person1; // person2也指向了person1的地址 0x1111 person1和person2 通用一个数据
// 修改了person2 person1也会发生改变
// person2.name = '八戒';
// console.log(person1);
// person2 和person1 共同指向了同一个地址
// console.log(person1 === person2); // true
// let o={};// 开辟了一个内存
// let o2={};// 开辟了另外一个内存
// console.log(o===o2);// false 两个不同的内存地址
/*
构造函数想要解决 性能问题
1 一定会把方法-函数写在构造函数的外面
2 再通过this.say 指向外部的函数
*/
</script>
6.构造函数-性能问题(2)
<script>
// 构造函数的 方法 都会通过类似的这种方式 来实现 多个实例的方法共享
function say() {
console.log("你好");
}
function CreatePerson(name) {
this.nickname = name;
this.say = say;
}
// function say() {
// console.log("学生你好");
// }
// function createStudent(params) {
// }
const obj1 = new CreatePerson("悟空");
const obj2 = new CreatePerson("八戒");
console.log(obj1);
console.log(obj2);
console.log(obj1.say === obj2.say); // true 这个代码是合理的 优化过
console.log(obj1.say === obj2.say); // false 不够好 性能不够好 两个say占据了两个内存
// 函数函数 方法提取出去 这套代码
// 优点: 方便代码维护、也解决了性能 obj1.say === obj2.say
// 缺点: 代码不够优雅 污染了全局变量 以后不能写 say方法,很容易就覆盖()
</script>
7.构造函数
<script>
// 构造函数 创建不同人 大家有大家的名字, 共同一个行为 say => 说出自己的名称
function CreatePerson(name, height) {
this.name = name;
this.height = height;
// this.say = function () {
// // console.log(name);
// console.log(this.name);
// };
}
CreatePerson.prototype.say = function () {
// this 指向了实例
// 通过this 实现了 数据传递 =访问到另外一个函数(构造函数)中的数据
console.log(this.name, this.height); // 出错
};
const obj1 = new CreatePerson("八戒", 100);
const obj2 = new CreatePerson("悟空", 150);
obj1.say();
obj2.say();
</script>
8.原型对象
(1)在构造函数的原型上 存放函数,原型对象 是任何构造函数对存在的一个对象 prototype
(2)作用:解决了同一个 say 浪费 内存的问题、解决了污染全局变量的问题
(3)案例
<script>
function CreatePerson(name) {
this.name = name;
}
// 原型对象
// console.log(CreatePerson.prototype);
// 在DNA上新增 东西
CreatePerson.prototype.say = function () {
console.log("你好");
};
const obj1 = new CreatePerson("悟空");
const obj2 = new CreatePerson("八戒");
// obj1.say();
// obj2.say();
function CreateStudent() {}
CreateStudent.prototype.say = function () {
console.log("学生你好");
};
// console.log(obj1.say === obj2.say);// 没有性能问题
// 有污染全局变量的问题吗 没有
// CreatePerson.prototype.say
// CreateStudent.prototype.say
// 小结 原型对象-构造函数 一般情况
// 构造函数内只放属性 name 、age、color、height
// 对应原型上 都是放 方法 = 函数
</script>
9.面向对象体验
<body>
<button class="btn1">控制图片1</button>
<script>
/*
需求: 通过 new MyImg("图片地址") 页面上就会多一个图片标签
1 页面上多一个图片的本质代码
1 const img = document.createElement("img");
2 img.src="图片地址"
3 document.body.appendChild(img);
2 new的方式来创建图片
new MyImg 做了什么事情 => 调用了一个构造函数 MyImg
通过 点击了按钮,控制对应的图片 放大缩小效果
1 css来实现放大缩小
2 按钮 绑定点击事件
*/
// const img1 = new MyImg('./images/1.png'); // 页面上多一个图片标签
function MyImg(src) {
const img = document.createElement("img");
img.src = src;
document.body.appendChild(img);
this.dom = img; // 把图片dom元素 添加到 this对象的一个属性 dom属性上了
}
MyImg.prototype.scale = function () {
// 图片放大缩小的本质是不是给图片的dom元素 添加一个class
// 获取一下 上一个函数中的一个变量 img
// 原型上 想要获取另外一个函数中的变量
// console.log(this.dom);
this.dom.classList.add("scale");
};
const imgModel = new MyImg("./images/gotop.png"); // 创建了一个对象
const btn1 = document.querySelector(".btn1");
btn1.addEventListener("click", function () {
imgModel.scale(); // 要调用这个对象的放大缩小的方法
});
</script>
</body>
10.面向对象
<body>
<button class="btn1">控制图片1</button>
<script>
function MyImg(src) {
const img = document.createElement("img");
img.src = src;
document.body.appendChild(img);
this.dom = img;
}
MyImg.prototype.scale = function () {
this.dom.classList.add("scale");
};
const imgModel1 = new MyImg("./images/gotop.png");
const imgModel2 = new MyImg("./images/b_07.jpg");
const imgModel3 = new MyImg("./images/b_08.jpg");
const btn1 = document.querySelector(".btn1");
btn1.addEventListener("click", function () {
imgModel1.scale();
imgModel2.scale();
imgModel3.scale();
});
/*
小的项目 用不到所谓的面向对象
复杂业务 面向对象技术需要(构造函数、this、原型对象)
*/
</script>
</body>
11.面向对象案例
<body>
<button>修改颜色</button>
<script>
/*
需求:
1 通过行代码 const divModel = new Div("这个是普通的地址"); 页面中出现对应的一个div标签
2 给按钮绑定点击事件 触发了
divModel.changeColor("red"); 这个div的背景颜色变成红色
divModel.changeColor("yellow"); 这个div的背景颜色变成黄色
分析:
1 Div 是一个构造函数
2 Div 构造函数 在原型上有一个方法 changeColor
3 const divModel = new Div("这个是普通的地址");
这行代码实际的作用 页面中出现一个div
1 const div=document.createElement("div");
2 div.innerText="文本内容"
3 document.body.appendChild(div)
4 divModel.changeColor("yellow"); 这个div的背景颜色变成黄色
???.style.backgroundColor="yellow"
*/
function Div(text) {
const div = document.createElement("div");
div.innerText = text;
document.body.appendChild(div);
this.dom = div;
}
Div.prototype.changeColor = function (color) {
// this.dom = div;
this.dom.style.backgroundColor = color;
};
Div.prototype.changSize = function (size) {
// this.dom = div;
this.dom.style.fontSize = size;
};
const button = document.querySelector("button");
const divModel1 = new Div("这个是普通的div1");
button.addEventListener("click", function () {
divModel1.changeColor("red");
// 新功能
divModel1.changSize("100px"); // 希望div中的文字 大小变为100px
});
</script>
</body>