面向后端的前端技术分享

分享时长: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中应用breakreturn等都不会跳出循环。

上列操作能够转换为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,用于革除。