[TOC]
# 第二部分总结(专题系列)
## 防抖与节流
防抖和节流的作用都是防止函数多次调用,区别在于,假设一个用户一直触发这个函数,且每次触发函数的时间间隔小于wait,防抖的情况下只会调用一次,而节流的情况会每隔一定时间调用函数
~~~
// 防抖
function debounce(func, wait, immediate) {
var timeout, result;
var debounced = function () {
var context = this;
var args = arguments;
if (timeout) clearTimeout(timeout);
if (immediate) {
// 如果已经执行过,不再执行
var callNow = !timeout;
timeout = setTimeout(function(){
timeout = null;
}, wait)
if (callNow) result = func.apply(context, args)
}
else {
timeout = setTimeout(function(){
func.apply(context, args)
}, wait);
}
return result;
};
debounced.cancel = function() {
clearTimeout(timeout);
timeout = null;
};
return debounced;
}
~~~
这个防抖函数和最普通的防抖函数相比关注了以下几个需求:
- this 和 event 的指向都要正确
- 允许立即执行
- 能返回函数的执行结果
- 能取消然后重新触发
~~~
// 节流
function throttle(func, wait) {
var timeout;
return function() {
context = this;
args = arguments;
if (!timeout) {
timeout = setTimeout(function(){
timeout = null;
}, wait)
// 立即执行
func.apply(context, args)
}
}
}
~~~
这样实现的节流函数满足了这样一个需求:鼠标移入能立刻执行,停止触发的时候还能再执行一次(假设事件处理程序是 onmousemove)
## 数组去重
尝试写一个名为 unique 的工具函数,我们根据一个参数 isSorted 判断传入的数组是否是已排序的,如果为 true,我们就判断相邻元素是否相同,如果为 false,我们就使用 indexOf 进行判断
~~~
var array1 = [1, 2, '1', 2, 1];
var array2 = [1, 1, '1', 2, 2];
// unique 工具函数用于数组去重
function unique(array, isSorted) {
var res = [];
var seen = [];
for (var i = 0, len = array.length; i < len; i++) {
var value = array[i];
if (isSorted) { // 如果数组是排序过的,判断当前元素与前一个元素是否相等
if (!i || seen !== value) {
res.push(value)
}
seen = value;
}
else if (res.indexOf(value) === -1) { // 如果数组是未排序的,使用 indexOf 方法
res.push(value);
}
}
return res;
}
console.log(unique(array1)); // [1, 2, "1"]
console.log(unique(array2, true)); // [1, "1", 2]
~~~
在数组中元素有一些特殊类型如对象、NaN的情况下,不同的数组去重方法可能会有不同的返回值
~~~js
// demo1
var arr = [1, 2, NaN];
arr.indexOf(NaN); // -1
~~~
indexOf 底层还是使用 === 进行判断,因为 NaN === NaN的结果为 false,所以使用 indexOf 查找不到 NaN 元素
~~~js
// demo2
function unique(array) {
return Array.from(new Set(array));
}
console.log(unique([NaN, NaN])) // [NaN]
~~~
Set 认为尽管 NaN === NaN 为 false,但是这两个元素是重复的。
## 快速获取数组的最大值和最小值
使用 `Math.max()`函数需要注意的问题:
1. 如果有任一参数不能被转换为数值,则结果为 NaN。
2. max 是 Math 的静态方法,所以应该像这样使用:Math.max(),而不是作为 Math 实例的方法 (简单的来说,就是不使用 new )
3. 如果没有参数,则结果为`-Infinity`(注意是负无穷大)
1.如果任一参数不能被转换为数值,这就意味着如果参数可以被转换成数字,就是可以进行比较的,比如:
~~~js
Math.max(true, 0) // 1
Math.max(true, '2', null) // 2
Math.max(1, undefined) // NaN
Math.max(1, {}) // NaN
~~~
2.如果没有参数,则结果为 -Infinity,对应的,Math.min 函数,如果没有参数,则结果为 Infinity,所以:
```
var min = Math.min();
var max = Math.max();
console.log(min > max);
```
结合ES6的扩展运算符使用
```
var arr = [6, 4, 1, 8, 2, 11, 23];
console.log(Math.max(...arr))
```
## 惰性函数
我们看下面的这个例子,在 DOM 中添加事件时需要兼容现代浏览器和 IE 浏览器(IE < 9),方法就是对浏览器环境进行判断,看浏览器是否支持,简化写法如下。
~~~js
// 简化写法
function addEvent (type, el, fn, capture = false) {
if (window.addEventListener) {
el.addEventListener(type, fn, capture);
}
else if(window.attachEvent){
el.attachEvent('on' + type, fn);
}
}
~~~
但是这种写法有一个问题,就是每次添加事件都会调用做一次判断,那么有没有什么办法只判断一次呢?可以利用闭包和立即调用函数表达式(IIFE)来处理。
~~~js
const addEvent = (function(){
if (window.addEventListener) {
return function (type, el, fn, capture) {
el.addEventListener(type, fn, capture);
}
}
else if(window.attachEvent){
return function (type, el, fn) {
el.attachEvent('on' + type, fn);
}
}
})();
~~~
也可以使用惰性函数来处理
~~~
function addEvent (type, el, fn, capture = false) {
// 重写函数
if (window.addEventListener) {
addEvent = function (type, el, fn, capture) {
el.addEventListener(type, fn, capture);
}
}
else if(window.attachEvent){
addEvent = function (type, el, fn) {
el.attachEvent('on' + type, fn);
}
}
addEvent(type, el, fn, capture); // 这一步是关键
}
~~~
第一次调用`addEvent`函数后,会进行一次环境判断,在这之后`addEvent`函数被重写,所以下次调用时就不会再次判断环境。
- 序言 & 更新日志
- H5
- Canvas
- 序言
- Part1-直线、矩形、多边形
- Part2-曲线图形
- Part3-线条操作
- Part4-文本操作
- Part5-图像操作
- Part6-变形操作
- Part7-像素操作
- Part8-渐变与阴影
- Part9-路径与状态
- Part10-物理动画
- Part11-边界检测
- Part12-碰撞检测
- Part13-用户交互
- Part14-高级动画
- CSS
- SCSS
- codePen
- 速查表
- 面试题
- 《CSS Secrets》
- SVG
- 移动端适配
- 滤镜(filter)的使用
- JS
- 基础概念
- 作用域、作用域链、闭包
- this
- 原型与继承
- 数组、字符串、Map、Set方法整理
- 垃圾回收机制
- DOM
- BOM
- 事件循环
- 严格模式
- 正则表达式
- ES6部分
- 设计模式
- AJAX
- 模块化
- 读冴羽博客笔记
- 第一部分总结-深入JS系列
- 第二部分总结-专题系列
- 第三部分总结-ES6系列
- 网络请求中的数据类型
- 事件
- 表单
- 函数式编程
- Tips
- JS-Coding
- Framework
- Vue
- 书写规范
- 基础
- vue-router & vuex
- 深入浅出 Vue
- 响应式原理及其他
- new Vue 发生了什么
- 组件化
- 编译流程
- Vue Router
- Vuex
- 前端路由的简单实现
- React
- 基础
- 书写规范
- Redux & react-router
- immutable.js
- CSS 管理
- React 16新特性-Fiber 与 Hook
- 《深入浅出React和Redux》笔记
- 前半部分
- 后半部分
- react-transition-group
- Vue 与 React 的对比
- 工程化与架构
- Hybird
- React Native
- 新手上路
- 内置组件
- 常用插件
- 问题记录
- Echarts
- 基础
- Electron
- 序言
- 配置 Electron 开发环境 & 基础概念
- React + TypeScript 仿 Antd
- TypeScript 基础
- 样式设计
- 组件测试
- 图标解决方案
- Algorithm
- 排序算法及常见问题
- 剑指 offer
- 动态规划
- DataStruct
- 概述
- 树
- 链表
- Network
- Performance
- Webpack
- PWA
- Browser
- Safety
- 微信小程序
- mpvue 课程实战记录
- 服务器
- 操作系统基础知识
- Linux
- Nginx
- redis
- node.js
- 基础及原生模块
- express框架
- node.js操作数据库
- 《深入浅出 node.js》笔记
- 前半部分
- 后半部分
- 数据库
- SQL
- 面试题收集
- 智力题
- 面试题精选1
- 面试题精选2
- 问答篇
- Other
- markdown 书写
- Git
- LaTex 常用命令