笔记-22/03/12-代码常见优化

对于代码好坏应该多维度去看待(易维护性、效率等,不能只看执行速度)

1. 循环添加事件

在这样循环添加事件的情况下是添加失败的 i会输出相同的值

for(var i = 0;i < len; i++){
    button[i].onclick = function() {
        console.log(i)
    }
}

实际上是因为闭包的原因,因为for循环只会申请一片空间进行使用,而function中的i引用了外部的i,在循环完成后i值为3,此时的函数如果触发那么函数上下文的AO中没有i这个值,就会向外部找,打个比方 在EC(G)中找到了i,然后使用了这个i;而不会去管是谁去触发这个事件的;

解决方案有很多,可以添加自执行函数:

for(var i = 0;i < len; i++){
    (function(i){
        button[i].onclick = function() {
            console.log(i)
        }
    })(i)
}

for(var i = 0;i < len; i++){
    button[i].onclick = (function(i) {
        return function() {
            console.log(i)
        }
    })(i)
}

        这样使用自执行函数,会额外生成多个函数作用域去执行,每次函数执行时都能通过自身函数作用域中的AO或父级作用域链中父级的执行上下文中的AO去获取i,而不用去EC(G)中访问i;缺点是:因为最后onclick绑定的函数是在匿名函数上下文生成的,所以这些匿名函数的上下文无法被释放,这样做消耗了更多的空间;

        除此之外也可以使用let关键字来声明i,let同样会生成块级作用域,每个块级作用域中都会使用各自的i;同样的因为用到了闭包的思想 所以同样会占用更多的空间

        在其他就是添加自定义属性:每次循环时给item添加一个自定义属性,执行方法时使用自身的属性;(优点:相比使用闭包的思想减少了空间的占用)

        事件委托: 没有使用闭包,也没有添加自定义的字段,相比来说是最好的

2. 变量局部化 和 减少访问层级

        提高代码执行效率(减少了作用域链的查找路径)

3. 缓存数据

        对于多次使用,但对值的实时要求低的情况可以缓存 减少作用域链或其他方式查找的消耗;

4. 防抖、节流

        滚动事件、输入的模糊查询、点击操作

        浏览器默认会有自己的监听事件间隔(4-6ms),上述事件不需要这么频繁的触发造成了资源浪费;

        防抖:对于这些高频操作 只希望识别一次点击 可以第一次或最后一次;

        节流:对于高频操作,可以自己设置频率,让高频的触发按照定义的频率触发;

const myDebounce = function (handle, immediate, wait) {
				if (typeof handle !== "function")
					return new Error("handle must be a function");
				if (typeof immediate === "undefined") immediate = false;
				if (typeof wait !== "number") wait = 300;

				let timer = null;
				return function (...args) {
                    let self = this;
					clearTimeout(timer);
                    (immediate && !timer) ? handle.call(self, ...args) : 1;
					timer = setTimeout(() => {
                        timer = null;
						immediate || handle.call(self, ...args);
					}, wait);

				};
			};
function myThrottle(handle, wait) {
				if (typeof handle !== "function")
					throw new Error("handle must be an function");
				if (typeof wait === "undefined") wait = 400;

				let previous = 0;
				let timer = null;
				return function (...args) {
					let self = this;
					let now = new Date();
					let interval = wait - (now - previous);
					if (interval <= 0) {
						clearTimeout(timer);
						timer = null;
						// 这里清楚定时器  主要是防止触发事件同一时刻 之前settimeout的时间也到了 导致重复调用回调函数
						// 距离上次触发超过了wait  执行
						handle.call(self, ...args);
						previous = new Date();
					} else if (!timer) {
						timer = setTimeout(() => {
							timer = null;
							handle.call(self, ...args);
							previous = new Date();
						}, interval);
					}
				};
			}

5. 减少判断层级

        不满足条件时提前return  减少多层判断的嵌套

6. 减少循环体内活动

        减少循环体内公用的数据或代码(如length的获取可以提到前面)

7. 字面量和构造式

        对于引用类型,采用构造方式创建和字面量创建({}[]...)速度相差不大 构造稍慢一些;

        对于基本数据类型  采用构造方式创建 比 字面量创建速度慢很多

                字面量方式创建的变量 在调用方法时 会隐式将其转为一个对象去调用它原型链上的方法

        

         字面量形式创建的string会比构造出来的快

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值