JavaScript day14

118 阅读6分钟

Function

作用域:2种
	1、全局:随处可用,可以被反复使用,缺陷:容易被污染

	2、局部:只能在函数调用时内部可用,不会被污染,缺陷:一次性的,是会自动释放的

*函数的执行原理:

1、程序加载时:

		创建执行环境栈(ECS):保存了函数调用的顺序的数组
		首先压入全局执行环境(全局EC)
		全局EC引用着全局对象window
		window中保存着全局变量

程序加载时.png

2、定义函数时:

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

定义函数时.png

3、调用前:

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

调用前.png

4、调用时:

正是因为有了前三个步骤,我们才有了变量的使用规则:优先使用局部的,局部没有找全局,全局没有则报错

调用时.png

5、调用完:

函数的EC会出栈,AO无人引用,垃圾回收器登场,AO自动释放,局部变量也就自动释放

调用完.png

*两链一包:

作用域链:以函数的EC为起点,经过AO,【逐级引用】,形成的一条链式结构我们就称之为叫做作用域链
作用:查找变量,带来了变量的使用规则

原型链:今天不管
 
闭包

*闭包

闭包:希望保护一个可以【反复使用的局部变量】的一种词法结构,其实还是是一个函数

何时:保护一个可以【反复使用的局部变量】

如何使用:

		1、两个函数进行嵌套
		2、外层函数创建受保护的变量
		3、外层函数return出内层函数
		4、内层函数要去操作受保护的变量

强调:

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

最简单的b包.png

缺陷:

受保护的变量,永远不会被释放,使用过多,会导致内存泄漏

问题:应该在哪里使用?使用场景:防抖节流

应该在哪里使用?使用场景:防抖节流
		
		三个事件需要防抖节流:
			1、elem.onmousemove - 频繁的修改DOM树,影响性能
			2、input.oninput - 每次input的内容修改都会触发,性能不好
			3window.onresize - 窗口大小触发事件

			xxx.以上三个事件=function(){
				inner();
			}

		公式:
		function fdjl(){
			var timer=null;//局部的timer准备保存定时器,定时器的序号
			return function(){
				if(timer!==null){clearTimeout(timer)}//停止一次性定时器
				timer=setTimeout(function(){
					操作即可!
				},1000)
			}
		}
		var inner=fdjl();

防抖节流案例1

防抖节流案例.png

防抖节流效果.png

防抖节流案例2

防抖节流窗口大小事件.png

窗口大小事件.png

*Object

Object:对象 - Array/String/Function/RegExp... 都是前辈们提前创建好的,我们现在要学习的是自定义对象

面向对象:三大特点:封装、继承、多态

面向过程:经过:开始 -> 结束,我们一直的开发方式都是面向过程:先干什么再干什么最后干什么

为什么要面向对象:现实生活中所有的数据都必须包含在一个事物中才有意义
何时要使用面向对象开发方式:以后做任何操作都要封装在一个对象中 - 非常的不适合初学者

笔试题

1、*鄙视题:简单的说一说 面向对象 和 面向过程 开发方式的区别?
面向对象:对象(属性和方法),js有一句话万物皆对象,假设一个人是一个对象的话
属性:身高、体重、姓名、性别、年龄、智商、情商、发色...
方法:吃饭、睡觉、拉屎、跑步、喝水、唱歌...
所有的东西都要放在一个对象之中,才显得更有意义

面向过程:经过:开始 -> 结束,我们一直的开发方式都是面向过程:先干什么再干什么最后干什么

封装:创建自定义对象:3种方式

1、*直接量:

		var obj={
			"属性名":属性值,
			...
			"方法名":function(){操作},
			...
		};

特殊:
        1、其实属性名和方法名的""可以不加的,暂时不推荐,因为以后我们要学习一种数据格式JSON,要求属性名和方法名必须是一个"",单引号都不可以,为了习惯,我们就一直加上使用
	2、访问对象的属性和方法
				*obj.属性名	===	obj["属性名"]
				*obj.方法名()	===	obj["方法名"]();
				***js有一句话万物皆对象,一切对象的底层都是hash数组
	3、访问到不存在的属性,返回undefined
	4、可以随时随地的添加新属性和方法
	5、希望遍历出对象所有的东西,使用for in循环
	6、***如果你希望再对象的方法里使用对象自己的属性:this.属性名

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

2、预定义构造函数方式

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

以上两个方法预定义构造函数方式和直接量都有一个缺陷:一次只能创建一个对象

3、自定义构造函数:批量创建

批量创建对象:【自定义】构造函数方式		
		
1、创建自定义构造函数
			function 类名/构造函数名(形参1,形参2,...){
				this.属性名1=形参1;
				this.属性名2=形参2;
			}
		
2、调用构造函数创建出对象
		var obj1=new 构造函数名(实参1,实参2,...)
		var obj2=new 构造函数名(实参1,实参2,...)

封装面向对象选项卡

封装面向对象选项卡.png

面向对象:优缺点

面向对象
优点:

1、逼格高,所有的属性和方法都保存在一个对象之中 - 更符合现实生活
2、每个功能特地分开写 - 便于后期维护,哪怕没有注释,我也能一眼看懂代码
3、铁锁链舟 - 一个方法触发多个方法联动

缺点:对新手不友好,this的指向变来变去的