前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 ># JavaScript 专题之 This 和定时器

# JavaScript 专题之 This 和定时器

作者头像
九旬
发布2023-10-18 18:02:52
1460
发布2023-10-18 18:02:52
举报
文章被收录于专栏:九旬大爷九旬大爷

# JavaScript 专题之 This 和定时器

前端技术分享(2021-05-10) 1.png
前端技术分享(2021-05-10) 1.png

分享时长:45 分钟分享+15 分钟提问

分享两个在 JS 中非常重要、但又经常遇到问题的两个点。

思维导图:https://naotu.baidu.com/file/7d05ddb397c649f62136040993cbd04bopen in new window

# 目的

  • 分享日常开发工作中常遇到的问题
  • 提升工作效率,编写易维护的代码
  • 了解前端技术的趋势

# This

JS 关键字:指向当前环境的上下文

# 1. 事件中的 this

在 DOM 事件中,this指向当前的 DOM 元素对象。

在 HTML 事件(仅为 addEventListener 添加时),this 指向了接收事件的 HTML 元素

代码语言:javascript
复制
<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
代码语言:javascript
复制
function func() {
  console.log(this); // Window or global
}
func();

# 3. 对象的方法调用

this 指向当前的对象

代码语言:javascript
复制
const xiaoming = {
  name: "小明",
  getName() {
    console.log(this.name);
  },
};
xiaoming.getName(); // 小明

# 4. 构造函数内调用,this 指向实例对象

代码语言:javascript
复制
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 指向第一个参数

代码语言:javascript
复制
const xiaoming = {
  name: "小明",
  getName() {
    console.log(this.name);
  },
};
const xiaohong = {
  name: "小红",
};
xiaoming.getName.call(xiaohong); // 小红

# this 复制引用

原因: 用于纠正 this 指向不达预期的问题

应用场景: 比如在 setTimeout 中的函数

用法:let that = this;

普通函数 VS 箭头函数

代码语言:javascript
复制
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(); // 普通函数 obj
obj.outout2(); // 普通函数 obj

因为箭头函数的this是在定义的时候就确定的,使用它可以少写一步 this 指向,推荐使用。

# 定时器

  • setTimeout:规定 N 秒后执行
  • setInterval:规定 N 秒后循环执行

# 参数

  • 函数/字符串、字符串会触发eval()
  • 时长毫秒(ms)
  • 传入函数的参数列表

传入函数

代码语言:javascript
复制
// 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 的和,然后输出。

传入字符串

代码语言:javascript
复制
setTimeout("alert(0)", 2000);

1

可以接受一个字符串,默认通过 eval() 解析后执行,但是 eval 函数非常耗性能,非特殊不推荐。

# 返回值

返回定时器的 ID ,用于清除定时器。

代码语言:javascript
复制
clearInterval(n);
clearTimeout(n);

# setTimeout

核心逻辑:N 秒推入执行栈,而不是 N 秒后执行,

使用场景:延迟执行某个操作时

问题:

  • 设置 0 秒也会在下一个宏任务中执行(异步)
  • 定时器在 for 中输出 1-10 的坑(forEach 不可跳出循环)

异步

代码语言:javascript
复制
// for & setTimout
for (var i = 1; i <= 10; i++) {
  setTimeout(() => {
    console.log(i); // ??
  }, 1000);
}

因为异步的原因,setTimeout 被延迟到下一次事件循环中执行。

forEach

forEach 不能跳出循环

代码语言:javascript
复制
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操作

代码语言:javascript
复制
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 轮询,每一秒查询一次数据。

代码语言:javascript
复制
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的话会一直保存在内存中,造成内存泄漏。
  • 使用场景:保存学时、人脸识别、考试倒计时等
  • 多个页面栈共享定时器
weapp-time.png
weapp-time.png

# 解决方法

定时器不准确

解决方法:使用settimeout模拟setinterval

代码语言:javascript
复制
// 自定义一个定时器
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);

定时器太多清楚不掉,造成内存泄漏

解决方法:批量清楚定时器

代码语言:javascript
复制
// 清楚当前页面的所有定时器
for (let i = 1; i < 100000; i++) {
  clearInterval(i);
  clearTimeout(i);
}

建议及时保存定时器的id,用于清除。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • # JavaScript 专题之 This 和定时器
    • # 目的
      • # This
        • # 1. 事件中的 this
        • # 2. 全局函数、匿名函数,this 指向是全局对象
        • # 3. 对象的方法调用
        • # 4. 构造函数内调用,this 指向实例对象
        • # 5. call/apply/bind 调用
        • # this 复制引用
      • # 定时器
        • # 参数
        • # 返回值
        • # setTimeout
        • # setInterval
        • # 问题
        • # 解决方法
    相关产品与服务
    人脸识别
    腾讯云神图·人脸识别(Face Recognition)基于腾讯优图强大的面部分析技术,提供包括人脸检测与分析、比对、搜索、验证、五官定位、活体检测等多种功能,为开发者和企业提供高性能高可用的人脸识别服务。 可应用于在线娱乐、在线身份认证等多种应用场景,充分满足各行业客户的人脸属性识别及用户身份确认等需求。
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档