十三:以理论结合实践方式梳理前端 ES 6+ ——— ES 6+ 事件处理

函数防抖与函数节流

对于某些 高频触发 的事件,如果事件处理函数的调用频率没有限制的话,那么将会大大加重浏览器的负担

这时我们可以采用防抖函数或节流函数,减少事件处理函数的调用频率,同时保证不会影响用户体验

防抖函数

场景:在触发事件 n 秒后,才会执行事件处理函数,如果 n 秒内再次触发,那么重新计时

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Debounce</title>
    <script>
        function debounce(handler, delay) { // 防抖函数
            var timer = null
            return function () {
                var that = this
                var args = arguments
                if (timer) clearTimeout(timer)
                timer = setTimeout(function() { handler.apply(that, args) }, delay)
            }
        }
        function show() { // 代理 log 方法
            console.log.apply(console, arguments)
        }
        let debounce_show = debounce(show, 1000)
    </script>
</head>
<body>
    <button onclick="debounce_show('Hello', 'World')">Debounce</button>
</body>
</html>

节流函数

防抖函数有一个问题,假如这个事件一直触发,那么这个事件的处理函数将永远无法执行

而使用节流函数可以解决这个问题,当持续触发事件时,节流函数可以保证一定时间内调用一次处理函数

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Debounce</title>
    <script>
        function throttle(handler, waitTime) { // 节流函数
            var timer = null
            var lastTime = Date.now()
            return function () {
                var that = this
                var args = arguments
                var currTime = Date.now()
                var remaining = waitTime - (currTime - lastTime)
                if (timer) clearTimeout(timer)
                if (remaining <= 0) {
                    handler.apply(that, args)
                    lastTime = Date.now()
                } else {
                    timer = setTimeout(function() { handler.apply(that, args) }, waitTime)
                }
            }
        }
        function show() { // 代理 log 方法
            console.log.apply(console, arguments)
        }
        let throttle_show = throttle(show, 1000)
    </script>
</head>
<body>
    <button onclick="throttle_show('Hello', 'World')">Throttle</button>
</body>
</html>

深拷贝和浅拷贝的理解

简单点来说,就是假设 B 变量复制了 A 变量,当修改 A 变量时,看 B 变量是否会发生变化,如果 B 变量也跟着变了,说明这是浅拷贝,拿人手短,如果 B 变量没变,那就是深拷贝,自食其力。

var a = 'aaa';
var b = a;
a = 'aaaaa';
console.log(a, b);				// a = aaaaa,b = aaa 深拷贝
var a = { name: 'aaa', age: 12 };
var b = a;
a.age = 10;
console.log(a, b);				// a = { name: 'aaa', age: 10 },b = { name: 'aaa', age: 10 } 浅拷贝

引用数据类型浅拷贝

对于基本数据类型,名字和值都会存储在栈内存中,并不存在浅拷贝的情况,但如果是引用数据类型,名字存在栈内存中,值存在堆内存中,但是栈内存会提供一个引用的地址指向堆内存中的值。

  • 当 b = a 进行拷贝时,其实复制的是 a 的引用地址,而并非堆里面的值。
  • 当 a.age = 10 时进行数组修改时,由于 a 与 b 指向的是同一个地址,所以自然 b 也受了影响,这就是所谓的浅拷贝了

实现深拷贝的方法

在拷贝引用数据类型时,为了不影响拷贝对象,需要将对象浅拷贝转化为深拷贝模式,达到互不干扰

(1)对象深拷贝推荐使用 ES6 扩展运算符

var a = { name: 'aaa', age: 12 };
var b = { ...a, age: 10 };
console.log(a, b);				// a = { name: 'aaa', age: 12 },b = { name: 'aaa', age: 10 }
--------------------------------------------------------------------------------------------------------------------------------
var a = { name: 'aaa', age: 12 };
var b = Object.assign({}, a);
b.age = 10;
console.log(a, b);				// a = { name: 'aaa', age: 12 },b = { name: 'aaa', age: 10 }

(2)数组深拷贝推荐使用 concat 方法

var a = [1, 2, 3, 4];
var b = [].concat(a);
b[2] = 6;
console.log(a, b);				// a = [1, 2, 3, 4],b = [1, 2, 6, 4]

传值方式

前端界面上的数据信息通常都是由后端提供的接口,通过查询数据库获取的,而有时候某个后端接口返回的数据可能在多个页面或板块中使用,那么就需要前端开发者进行传值处理,当然你重新去调用后端接口得到数据也可以呈现结果,若用户设备网络波动了一下,这样就没法取得数据,影响了用户体验,为了增强用户体验,强烈建议使用前端传值方式

路由传值

常用于页面之间进行值的传递,见于 get 请求,打开浏览器输入:www.baidu.com 在搜索输入框内输入 csdn 回车,查看浏览器地址栏信息发现

https://www.baidu.com/s?ie=utf-8&f=8&rsv_bp=1&rsv_idx=1&tn=baidu&wd=csdn&fenlei=256&rsv_pq=fe700cf10004535e&rsv_t=afbf6a%2BYix00Xyr79pftJRBUgD4IRXeWNmo0k%2F5JzzYVAEuasjD%2BbQrd0j8&rqlang=cn&rsv_enter=1&rsv_dl=tb&rsv_sug3=7&rsv_sug1=8&rsv_sug7=101&rsv_sug2=0&rsv_btype=i&inputT=5992&rsv_sug4=10935&rsv_sug=1


  • https://www.baidu.com/ 百度的搜索地址
  • https://www.baidu.com/s 百度提供的搜索接口
  • ?ie=utf-8&f=8&rsv_bp=1&rsv_idx=1&tn=baidu&wd=csdn… 路由参数

路由传值的格式给接口后面添加个问号,并以 & 链接多个参数对,且每个参数对都是以 key_name=key_value 格式,路由取参也是通过 key_name 来获取对应的参数的参数值的:

  • 首先需要通过 window.location.search 获取路由参数,
  • 然后将路由参数进行编辑处理,最终转化为 JSON 对象
  • 最后通过对象 .key_name 方式取得 key_name 参数值
var params = {};
var reg = new RegExp( "([^?=&]+)(=([^&]*))?", "g" );
window.location.search.replace(reg, ($0, $1, $2, $3) => params[$1] = $3);
console.log(params.wd);				// 输出结果:csdn

F12 进入 Console 控制台,执行上述代码,打印的正是搜索内容:csdn,试着将搜索输入框内的 csdn 换成中文的 “前端” 回车,再在控制台执行上述语句,打印的却是中文加密码:%E5%89%8D%E7%AB%AF,这里就需要进行中文解码:

var params = {};
var reg = new RegExp( "([^?=&]+)(=([^&]*))?", "g" );
window.location.search.replace(reg, ($0, $1, $2, $3) => params[$1] = decodeURI($3));
console.log(params.wd);				// 输出结果:前端
  • decodeURI() 函数用于解码 JS 中的 URL,它将编码的 URL 字符串作为参数并返回已解码的字符串
  • encodeURI() 函数用于在 JS 中对 URL 进行编码,它将 URL 字符串作为参数并返回编码的字符串

本地传值

对比路由传值,传递的路由参数只能在当前页面中使用,若存在共享多个页面或重启浏览器依然能够使用数据,则需要通过本地 storage 方式进行本地读写数据,将打开的控制台切换到 Application,观察左侧 storage 下面:Local Storage、Session Storage、Cookie【IndexDB、Web SQL 暂不考虑】

特性cookiesession storagelocal storage
数据生命周期生成时就会被指定一个 maxAge 值,默认关闭浏览器失效页面会话期有效可用除非被清楚,否则一直存在
存放数据大小数据不能超过 4kb(每个 http 请求都会携带 cookie)没有限制大小没有限制大小
与服务器通信参与服务器通信,后端接口可获取不参与服务器通信不参与服务器通信
使用是否简易需要自己封装 set、get自带 set、get、remove自带 set、get、remove
localStorage.setItem('localdata', 'local data string');
var localdata = localStorage.getItem('localdata');
console.log(localdata);									// local data string
localStorage.removeItem('localdata');

sessionStorage.setItem('sessiondata', 'session data string');
var sessiondata = sessionStorage.getItem('sessiondata');
console.log(sessiondata);								// session data string
sessionStorage.removeItem('localdata');

localStorage.clear();
sessionStorage.clear();
localStorage.setItem('localdata', JSON.stringify({ name: 'aaa', age: 12 }));
var localdata = localStorage.getItem('localdata');
console.log(localdata);									// "{ name: 'aaa', age: 12 }"
console.log(JSON.parse(localdata));						// { name: 'aaa', age: 12 }

标记属性传值

通过 HTML 5 的全局 data-* 属性进行值传递,常用于板块之间的数据传值,前端框架 vue、angule、react 组件传值就是一种标记属性传值的过程

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <button data-num="1" onclick="addNum(this)">+1</button>
    <script type="text/javascript">
        function addNum(doc) {
            var num = doc.getAttribute('data-num');
            +num++;         // 前面 + 将 num 转换为 Number 类型,后面 ++ 表自增加 1
            doc.setAttribute('data-num', num);
            doc.innerHTML = '+' + num;
        }
    </script>
</body>
</html>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值