1、闭包
作用域:2种
1、全局作用域:成员 随处可用,可以反复使用,但是容易被污染
2、函数作用域:成员 只有当前函数调用时内部可用,调用完了,就会释放了,一次性
函数的执行原理:
1、程序加载时:
创建执行环境栈(ECS):保存函数调用顺序的数组
首先压入全局执行环境(全局EC)
全局EC中引用着全局对象window
window中保存着全局变量
2、定义函数时:
创建函数对象:封装函数的定义
在函数对象中创建scope属性,记录着自己来自的作用域
全局函数的scope都是window
3、调用函数前:
在执行环境栈ECS压入新的函数的EC
创建活动对象AO:保存着本次函数调用时用到的局部变量
在EC中添加scope chain属性引用AO
设置AO的parent属性为函数的scope引用的对象
4、调用时:
变量的使用规则:优先使用局部的,局部没有才找全局,全局没有才报错
5、调用完:
函数的EC会出栈,AO会自动释放,局部变量也就自动释放了
作用域链scope chain:
以EC中的scope chain属性为起点,经过AO逐级引用,形成的一条链式结构,就称之为叫做作用域链
作用:查找变量
闭包目的:保护一个可以【反复使用的局部变量】的一种词法结构
结合了全局和局部的优点
唯一的缺点:受保护的变量永远不能释放,用多了会导致内存泄漏
尽量的少用:只有一个点会用到防抖节流
1、创建一个外层函数
2、在其中创建一个受保护的局部变量
3、外层函数调用要返回内层函数,此内层函数在操作受保护的变量
固定语法:
function 外层函数(){
受保护的变量;
return function(){
不断的操作受保护的变量
return 结果;
}
}
var 内层函数=外层函数();
正式开发:防抖节流:减少DOM树的渲染,DOM数据渲染的次数越频繁页面的效率越底下
需要去做防抖节流的3个事件:
1、elem.onmousemove - 鼠标移动事件,每次移动就会触发
2、input.oninput - input每次修改内容就会触发
3、window.onresize - 屏幕每次改变大小就会触发
固定公式:
function fdjl(){
var timer=null;
return function(){
//判断有没有定时器,如果有定时器就清除定时器
if(timer){clearTimeout(timer)}
timer=setTimeout(function(){
//你要做的操作
},毫秒数)
console.log(timer);//定时器的序号
}
}
var animate=fdjl();
2、Object:面向对象开发方式
三大特点(封装、继承、多态)
什么是面向对象:
在程序中都使用对象来描述现实中的一个事物,现实中事物的属性,代码中就成为了对象的属性,现实中事物的方法,代码中就成为了对象的函数,现实中所有数据都必须包含在一个事物中才有具体的意义
1、封装/创建/定义/声明/实例化:
自定义创建对象:3种
1、*直接量方式:(适合创建一个对象)
var obj={
"属性名":属性值,
...
"方法名":function(){},
...
}
强调:
①其实属性名和方法名的""可以省略,但是不推荐,以后JSON必须加""
②如何访问对象属性和方法
obj.属性名 === obj["属性名"]
obj.方法名(); === obj["方法名"]();
强烈建议:使用.去访问
③访问到不存在的属性:返回undefined
④也可以在后续随时随提的添加自己想要的东西
特殊:this在当前对象的方法内,指向的当前调用方法对象
面试题:this指向:
①单个元素绑定事件 this->单个元素
②多个元素绑定事件 this->当前触发的元素
③函数中也可以使用 this->当前调用函数的对象
④构造函数中如果出现了this this->当前正在创建的对象
⑤定时器中 this->window
只要以后对象的方法想要使用对象自己的属性,那么就写为this.属性名
2、预定义构造函数:
var obj=new Object();//空对象
obj.属性名=属性值;
...
obj.方法名=function(){}
...
以上两个方法仅适合创建单个对象,如果想要创建多个对象则太繁琐
3、*自定义构造函数:2步(适合创建多个对象)
①创建一个构造函数
function 类名(形参,...){
this.属性名=形参1;
this.属性名=形参2;
...
}
②反复调用构造函数创建出多个对象
var xxx=new 类名(实参,...)