面向后端的前端技术分享
分享时长:45 分钟 + 15分钟发问
分享两个在JS中十分重要、但又常常遇到的两个点。
目标
- 分享日常开发工作中常遇到的问题
- 晋升工作效率,编写易保护的代码
- 理解前端技术的趋势
This
JS 关键字:指向以后环境的上下文
1. 事件中的 this
在 DOM 事件中,this
指向以后的 DOM 元素对象。
在 HTML 事件(仅为 addEventListener
增加时),this
指向了接管事件的 HTML 元素
<style> #box { height: 300px; line-height: 300px; text-align: center; }</style><body> <div id="box">Hello World</div> <script> function bluify() { console.log(this); this.style.backgroundColor = "#00CCFF"; this.innerHTML = this.innerHTML === "Hello World" ? "你好,世界" : "Hello World"; } box.addEventListener("click", bluify, false); </script></body>
2. 全局函数、匿名函数,this 指向是全局对象
- 浏览器中指向
Window
- Node 环境指向
Global
function func() { console.log(this); // Window or global}func();
3. 对象的办法调用
this
指向以后的对象
const xiaoming = { name: "小明", getName() { console.log(this.name); },};xiaoming.getName(); // 小明
4. 构造函数内调用,this 指向实例对象
function Person(name, sex, age) { this.name = name; this.sex = sex; this.age = age;}let xiaoming = new Person("小明", "男", 20);console.log(xiaoming); // { name: '小明', sex: '男', age: 20 }
5. call/apply/bind 调用
this
指向第一个参数
const xiaoming = { name: "小明", getName() { console.log(this.name); },};const xiaohong = { name: "小红",};xiaoming.getName.call(xiaohong); // 小红
this 复制援用
起因: 用于纠正 this
指向不达预期的问题
利用场景: 比方在 setTimeout
中的函数
用法:let that = this;
一般函数 VS 箭头函数
var name = "window";let obj = { name: "obj", outout1() { let that = this; setTimeout(function() { console.log("一般函数", that.name); }, 1000); }, outout2() { setTimeout(() => { console.log("箭头函数", this.name); }, 1000); },};obj.outout1(); // 一般函数 objobj.outout2(); // 一般函数 obj
因为箭头函数的this
是在定义的时候就确定的,应用它能够少写一步 this
指向,举荐应用。
定时器
- setTimeout:规定 N 秒后执行
- setInterval:规定 N 秒后循环执行
参数
- 函数/字符串、字符串会触发
eval()
- 时长毫秒(ms)
- 传入函数的参数列表
传入函数
// setTimeout / setInterval 应用setTimeout( (...args) => { let sum = args.reduce((p, c) => p + c); console.log(args, sum); //[ 1, 2, 3 ] 6 }, 1000, 1, 2, 3);// 这段代码的意思是:在 1 秒后将这个函数推入执行栈,而后传递参数1,2,3到函数中
一秒后开始计算 1,2,3 的和,而后输入。
传入字符串
setTimeout("alert(0)", 2000);
能够承受一个字符串,默认通过 eval()
解析后执行,然而 eval
函数十分耗性能,非非凡不举荐。
返回值
返回定时器的 ID ,用于革除定时器。
clearInterval(n);clearTimeout(n);
setTimeout
外围逻辑:N 秒推入执行栈,而不是 N 秒后执行,
应用场景:提早执行某个操作时
问题:
- 设置 0 秒也会在下一个宏工作中执行(异步)
- 定时器在 for 中输入 1-10 的坑(forEach 不可跳出循环)
异步
// for & setTimoutfor (var i = 1; i <= 10; i++) { setTimeout(() => { console.log(i); // ?? }, 1000);}
因为异步的起因,setTimeout
被提早到下一次事件循环中执行。
forEach
forEach 不能跳出循环
let arr = [1, 2, 3];arr.forEach((e) => { console.log(e); 1, 2, 3; e += 1; if (e === 2) { // break !X // return !X }});console.log(arr); // [1, 2, 3];
在forEach
中应用break
、return
等都不会跳出循环。
上列操作能够转换为for
操作
for (let i = 0; i < arr.length; i++) { if (arr[i] === 2) { break; } arr[i] += 1;}console.log(arr); // [ 2, 2, 3 ]
setInterval
应用场景
- 视频学习的定时保留学时
- 扫码登录的轮询
问题
定时器不精确的起因
- N 秒后推入执行栈,而不是 N 秒后执行
- 会因为后面有代码在执行而导致工夫变短
案例代码:
假如有一个 HTTP 轮询,每一秒查问一次数据。
let startTime = new Date().getTime();let count = 0;setInterval(() => { let i = 0; while (i++ < 10000000); // 假如这里是查问数据带来的网络提早,用来减少每次函数执行的工夫 count++; console.log( "与原设定的距离时差了:", new Date().getTime() - (startTime + count * 1000), "毫秒" );}, 1000);
代码在执行屡次后,定时器会变得不精确,产生误差。
定时器不及时分明(小程序中)
- 不
clear
的话会始终保留在内存中,造成内存透露。 - 应用场景:保留学时、人脸识别、考试倒计时等
- 多个页面栈共享定时器
解决办法
定时器不精确
解决办法:应用settimeout
模仿setinterval
// 自定义一个定时器let timer = null;function interval(func, wait) { let interv = function() { func.call(null); timer = setTimeout(interv, wait); }; timer = setTimeout(interv, wait);}// 应用定时器interval(() => { let date = new Date(); console.log("log..", `${date.getMinutes()}: ${date.getSeconds()}`);}, 1000);// 分明定时器setTimeout(() => { clearTimeout(timer);}, 1000 * 6);
定时器太多分明不掉,造成内存透露
解决办法:批量分明定时器
// 分明以后页面的所有定时器for (let i = 1; i < 100000; i++) { clearInterval(i); clearTimeout(i);}
倡议及时保留定时器的id
,用于革除。