day14 闭包 防抖节流 对象

81 阅读6分钟

1、*****Function 作用域: 全局:随处可用,可以反复使用,缺点:容易被污染

	函数:只能在函数调用时内部使用,不会被污染的,缺点:一次性的,用完会自动释放

***函数的执行原理:
	1、程序加载时:
	     创建执行环境栈(ECS):保存函数调用顺序的数组
	     首先压入全局执行环境(全局EC)
	     全局EC引用着全局对象window
	     window中保存着全局变量

	2、定义函数时
	     创建函数对象:封装代码段
	     在函数对象中有一个scope(作用域)属性:记录着函数来自的作用域是哪里
	     全局函数的scope都是window

	3、调用前:
	      在执行环境栈(ECS)中压入新的EC(函数的EC)
	      创建出活动对象(AO):保存着本次函数调用用到的局部变量
	      在函数的EC中有一个scope chain(作用域链)属性引用AO
	      AO有一个parent属性是函数的scope引用着的对象

	4、调用时:正是因为前面三步:我们才有了变量的使用规则:优先使用局部的,局部没有找全局,全局没有就报错

	5、调用完:函数的EC会出栈,AO自动释放,局部变量也就自动释放了

	***面试题:两链一包
		作用域链:以函数的EC的scope属性为起点,经过AO,逐级引用,形成的一条链式结构,我们就称之为叫做作用域链
			作用:查找变量,带来了变量的使用规则:优先使用局部的,局部没有找全局,全局没有就报错
		闭包:希望保护一个可以【反复使用的局部变量】的一种词法结构
			作用:防抖节流
			缺点:内层泄漏

1、*****闭包:希望保护一个可以【反复使用的局部变量】的一种词法结构,其实函数一个函数,写法和以前有点不同
	何时使用:希望保护一个可以【反复使用的局部变量】的时候
	如何使用:
		1、两个函数进行嵌套
		2、外层函数创建受保护的变量
		3、外层函数返回return出内层函数
		4、内层函数要去操作受保护的变量

	强调:
		1、判断是不是闭包,有没有两个函数嵌套,返回内层函数,内层函数还在操作受保护的变量
		2、外层函数调用了几次,就创建了几个闭包,受保护的变量就有了几个副本
		3、同一次外层函数调用,返回的内层函数,都是在操作同一个受保护的变量

	缺点:受保护的变量,永远永远都不会被释放,使用过多,内层泄露 - 不可多用
	使用场景:防抖节流
		1、三个事件需要防抖节流
			1、elem.onmousemove - 鼠标移动事件
			2、input.oninput - 每次输入/删除就会触发
			3window.onresize - 每次你修改窗口尺寸都会触发
	
		防抖节流公式:
		function fdjl(){//停开停开停开停开停开停开停开停开停开停开停开停开停开停开停开停开停开停开停开停开停开
			var timer=null;
			return function(){
				if(timer!=null){clearTimeout(timer)}
				timer=setTimeout(function(){
					//操作
				},1000);
			}
		}
		var result=fdjl();
		此内层函数再在你需要事件中调用即可

2、*****Object:对象:Array、Function、Date、Math... 对象具有属性和方法,都是预定义好的,我们现在可以学习自定义对象 面向对象:三大特点:封装、继承、多态 1、***开发方式:2种 1、面向过程:经过 - 开始->结束,我们一直使用的开发方式都是面向过程:先干什么再干什么最后干什么 2、面向对象:对象(属性和方法),JS有一句话万物皆对象,假设一个人是一个对象的话: 属性:姓名、性别、年龄、身高、体重、爱好... 方法:吃饭、睡觉、拉粑粑、跑步、走路、学习... 为什么要面向对象:现实生活中所有的数据都必须包含在一个事物之中才有意义。更符合现实。 何时使用面向对象:以后做任何操作都要封装在一个对象里 - 建议:对初学者不太友好。

2、封装:创建自定义对象:3种方法
	1、*直接量方式:
		var obj={
			"属性名":属性值,
			...
			"方法名":function(){},
			...
		}

		强调:
			1、其实属性名和方法名的""可以省略 - 暂时建议你加上
			2、访问对象的属性和方法
				*obj.属性名;	===	obj["属性名"]
				*obj.方法名();	===	obj["方法名"]();
				***js中一切都是对象,一切对象的底层都是hash数组
			3、访问到不存在的属性,返回undefined
			4、可以随时随地添加新属性和新方法
				obj.属性名=属性值;
				obj.方法名=function(){};
			5、如果我们希望遍历出对象所有的东西,应该使用
				for(var i in lzh){
					console.log(lzh[i]);
				}
			6、*****如果你希望在对象的方法里使用到对象自己的属性:this.属性名;

			     *****难点:this的指向:
				1、单个元素绑定事件:this->单个元素
				2、多个元素绑定事件:this->当前触发事件的元素
				3、函数中使用this->谁在调用此方法,this指的就是谁
				4、定时器中的this->window
				5、箭头函数this->外部对象
				6、构造函数中的this->当前正在创建的对象

	2、预定义构造函数:var obj=new Object();//空对象
			//需要自己后续慢慢追加属性和方法
			obj.属性名=属性值;
			obj.方法名=function(){};

	以上两个方式都有一个缺陷:一次只能创建一个对象,适合创建单个对象的时候使用(第一种方式)

	3、*自定义构造函数:2步 - 适合创建批量对象
		1、创建自定义构造函数
			function 类名(name,age,hobby,...){
				this.name=name;
				this.age=age;
				this.hobby=hobby;
				...
			}
			//构造函数中的this->当前正在创建的对象
			//千万不要再里面创建方法,每个对象都会创建出一个方法,每一个方法/函数也是一个对象,浪费内存 - 下周一继承可以解决
		
		2、调用构造函数创建出对象
			var obj=new 类名(实参,...)

	面向对象:
		优点:
			1、逼格高,所有的属性和方法都保存在一个对象之中 - 更符合现实
			2、每个功能特地的分开写 - 哪怕不写注释,也便于以后维护
			3、铁锁链舟 - 一个方法触发多个方法联动

		缺点:对新手不友好,this的指向非常的恶心

作业: 0、博客 1、根据函数的执行原理来画图 2、防抖节流的三个事件都试一试 3、封装对象版 - 选项卡 4、封装对象版 - 轮播 5、封装对象版 - 购物车