批改状态:合格
老师批语:箭头函数, 可以强大的简化代码, 但代码 的可读性也会下降你的, 要注意
给原生的回调函数/匿名函数提供了一个更加简洁的书写方式
解决回调中this关键字的指向问题
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>箭头函数应用场景</title></head><body><script>// 1. 简化原生回调函数的书写方式let demo1 = function (name) {return name;};console.log(demo1("jack")); // jacklet demo2 = (name) => name;console.log(demo2("tom")); // tom// 用于遍历let arr = ["a", "b", "c", "d"];let ul = document.createElement("ul");let str = "";arr.forEach((item) => {str += `<li>我是${item}</li>`;});ul.innerHTML = str;document.body.appendChild(ul);// 2. 解决回调中this指向的问题let name = "outName";const p1 = {name: "p1的name",getName: function () {// 使用原生的回调方式 访问到的是全局namesetTimeout(function () {console.log(this.name);}, 500);},};p1.getName(); // outNameconst p2 = {name: "p2的name",getName: function () {// 使用箭头函数,访问到的是当前对象的namesetTimeout(() => {console.log(this.name);}, 500);},};p2.getName(); // p2的name// 通过上面示例理解如下两个问题:// 1. 普通回调函数中的this是指向全局的// 2. 箭头函数中实际上是没有this的,而箭头函数支持词法作用域(块级作用域),所以箭头函数中的// this指向 是根据它的作用域而判断到底是指向当前对象还是全局的// 3. 千万不能理解成箭头函数中的 this 就一定是指向当前对象,如下:const p3 = {name: "p3的name",getName: () => {console.log(this.name);},};p3.getName(); // outNameconst p4 = {name: "p4的name",getName: function () {console.log(this.name);},};p4.getName(); // p4的name// 从上面可以看出,p3的getName()方法使用箭头函数方式书写,但是其中的this指向了全局// 箭头函数理解这块困了我很久,最终我总结如下:// 如果箭头函数中存在this,那么这个this会和定义这个箭头函数的this绑定,简单的说,就是箭头函数的父函数的this是谁,那么箭头函数的this就是谁const p5 = {name: "p5的name",getName: () => {console.log(this); // WindowsetTimeout(() => {console.log(this.name);}, 500);},};p5.getName(); // outName// 1. setTimeout中的this会和getName中的this绑定,而getName中的this是Window,所以最终这个出现的this是全局const p6 = {name: "p6的name",getName: function () {console.log(this); // 当前对象setTimeout(() => {console.log(this.name);}, 500);},};p6.getName(); // p6的name// 2. 此时,getName的this和当前对象绑定了,所以setTimeout箭头函数中的this也绑定到了当前对象// 3. 最后总结:其实这个箭头函数也并不是哪里都适合用// 当我们不需要使用this对象的时候,可以放心大胆的用箭头函数来简化语法// 当我们需要this对象的时候,你得明确知道你需要的this是全局还是当前对象,然后再酌情使用,就像p5和p6的例子中,// 如果你需要当前对象,那么在父函数getName()中,你就不能使用箭头函数的语法来书写getName()</script></body></html>
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>箭头函数示例</title><style>p {background-color: black;color: white;line-height: 50px;width: 500px;text-align: center;}</style></head><body><form action="" method="post"><label for="idNumber">请输入用户id号:</label><input type="text" name="idNumber" id="idNumber" /><button>查询用户信息</button></form><p></p><script>// 示例:根据id获取对应的用户信息// 模拟用户数据const users = [["6001", "jack", 20, "male"],["8002", "alice", 21, "female"],["9003", "lisa", 22, "secret"],];// 获取 输入框,查询按钮,以及存放用于信息的P标签let idNumber = document.querySelector("#idNumber");let btn = document.querySelector("button");let p = document.querySelector("p");btn.addEventListener("click",(ev) => {// 禁用默认行为ev.preventDefault();// console.log(idNumber.value);show(idNumber.value);// 执行完 显示用户信息 这个函数以后,清空输入框并再次获得输入焦点idNumber.value = "";idNumber.focus();},false);// 显示用户信息的函数function show(idNum) {// 获取所有用户信息的id号let ids = [];users.forEach((user) => {ids.push(user[0]);});// console.log(ids);// 下面一定要用循环,千万不能用foreach,因为遍历不能中途停止循环,而这里要用到break,continue// 1. 找到对应的用户信息时,要break,终止循环// 2. 如果没找到对应的用户信息,就continue,继续执行for (let i = 0; i < ids.length; i++) {if (ids[i] == idNum) {users.forEach((user) => {if (user[0] == idNum) {// 解构当前找到的这个用户信息这个数组let [id, name, age, sex] = user;p.innerHTML = `用户姓名:${name},用户年龄:${age},用户性别:${sex}`;}});break;} else {p.innerHTML = "信息不存在";continue;}}}</script></body></html>

<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>ES6中的类的原理与实现</title></head><body><script>// 先看看ES6中的类class A {// 构造方法constructor(name) {this.name = name;}// 原型方法getName() {return this.name;}}let obj = new A("xixi");console.log(obj.getName()); // xixi// 下面了解一下类的原理与实现// 在原生js中是没有类的概念的,都是通过“构造函数”来模拟类;console.dir(function () {});console.log({});// 通过上面两行代码,在控制器中看到:// 1. 一个函数有2个属性:prototype(原型属性) __proto__(原型链属性)// 2. 一个对象有1个属性:__proto__// 下面使用构造函数来模拟 类的实现// 1. 声明一个构造函数function Demo(name) {// 属性this.name = name;// 方法this.getName = function () {return this.name;};}// 2. 实例化类let a = new Demo("jack");console.log(a.getName()); // jackconsole.log(a); // 在控制台中可以看到,a这个对象从Demo类中继承到了name属性和getName()方法// 但是为了防止代码的冗余,像一些公共方法通常都会写到它的原型属性上,这样的话,生成的对象也能自动继承方法,如下:function Demo1(name) {this.name = name;}// 公共方法Demo1.prototype.getName = function () {return this.name;};let b = new Demo1("alice");console.log(b.getName()); // aliceconsole.log(b); // 此时,getName()方法就跑到对象b的__proto__属性中去了,而且以后实例化生成的对象,它的__proto__属性中都会继承这个方法// 因此,通过函数的原型属性prototype,将它的指针对应一个方法的时候,new出来的对象,也都能继承这个方法,并保存在__proto__原型属性链中// 基于这一点,构造函数便模拟了类的实现(继承父类中的方法)// 总结:函数的两大属性// 1. prototype:当该函数做为构造函数使用时(new 函数名),并且使用此属性声明的方法能对应上新生成的对象的__proto__属性,才有意义// 2. __proto__:此属性指向对象的公共方法// 分析总结:// 1. 函数中为什么也有__proto__属性:因为函数也是属于对象// 2. 为什么使用prototype声明方法后,生成的对象就在__proto__属性中继承了方法?// a.在控制台中打开函数的prototype属性,可以看到在prototype属性中也有__proto__属性// b.__proto__属性:其实是原型链属性,类似生物链把,它应该是在对象的最顶层,就简单理解成父类把// c.当使用prototype声明方法时,这个方法就会保存在__proto__这个原型链属性中// d.当实例化这个构造函数生成一个新对象时,对象的__proto__属性必然会继承构造函数的__proto__属性,从而也就继承了方法</script></body></html>
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号