JS——作用域和闭包
1 知识点
1.1 执行上下文
- 执行上下文的范围:① 一段script(全局); ② 一个函数
- 在 “全局” or “函数” 范围内,以下变量会提升
全局:变量定义、函数声明
函数:变量定义、函数声明、this、arguments
(PS:注意“函数声明”和“函数表达式”的区别)
1.2 this
this 要在执行时才能确认值,定义时无法确认。
————————————————
*作为构造函数执行
*作为对象属性执行
*作为普通函数执行
*call apply bind(区别?)
1.3 作用域
作用域特点:
*没有块级作用域
*只有函数和全局作用域
// 无块级作用域
if (true) {
var name = 'zhangsan'
}
console.log(name) // zhangsan
// 函数和全局作用域
var a = 100;
function fn() {
var a = 200;
console.log('fn',a)
}
console.log('global', a) // global 100
fn() // fn 200
1.4 作用域链
自由变量:当前作用域没有定义的变量
作用域链——当前作用域找不到的变量定义会往父级作用域找
1.5 闭包
如何实现闭包?
*函数作为返回值
*函数作为参数传递
2 问答
题目:
*说一下对变量提升的理解
*说明 this 几种不同的使用场景
小延伸:call、apply、this的区别?使用场景?
*创建10 个 a 标签,点击的时候弹出来对应的序号
*如何理解作用域
*实际开发中闭包的应用
2.1 说一下对 变量提升 的理解
以下2者在执行时会提前先执行
*变量定义
*函数声明(注意和 函数表达式 的区别)
2.2 说明 this 几种不同的使用场景
this 表示 当前对象,this的指向 是根据 调用的上下文 决定的。
调用的上下文 包括 全局&局部。
- 全局环境——指向window对象
- 局部环境——
① (普通函数)全局环境直接调用函数,this 指向 window
② (对象函数)对象函数调用,哪个函数调用 this 就指向哪个对象
③ (构造函数)使用 new 实例化对象,在构造函数中的 this 指向实例化对象
④ (call、apply)使用 call 或 apply 改变 this 的指向
小延伸:call、apply、this的区别?使用场景?
区别
1)相同:
call、apply、bind可以将某个函数的this指向修改为传入这三个方法中的第一个参数,
2)不同:
其中call、apply会立即执行,bind返回的是一个函数,需调用后执行。
第二个参数是传入要执行的方法中的参数,call、bind是独立传递参数,apply是以数组传递参数的应用场景
1、需要改变某个函数的this指向时
2、当参数较少时可以使用call,参数较多可以使用apply以数组的方式传递
3、当需要重复调用时,可以使用bind新定义一个方法
var obj={
name:'Li lei',
intr:function( age, city ){
console.log(`我叫${
this.name},我${
age}岁,我来自${
city}`);
}
}
var obj2={
name:'Han meimei',
intr:function( age, city ){
console.log(`I'm ${
this.name},I'm ${
age} years old,I'm from ${
city}`);
}
}
obj.intr.call( obj2, 20, '中国' ); //我叫Han meimei,我20岁,我来自中国
obj.intr.apply( obj2, [ 20, '中国' ] ); //我叫Han meimei,我20岁,我来自中国
obj.intr.bind( obj2, 20, '中国' )(); //我叫Han meimei,我20岁,我来自中国
2.3 创建10 个 a 标签,点击的时候弹出来对应的序号
var i
for (i=0; i<10; i++) {
(function (i) {
var a = document.createElement('a')
a.innerHTML = i + '<br>'
a.addEventListener('click', function(e) {
e.preventDefault( )
alert(i)
})
document.body.appendChild(a)
}) (i)
}
2.4 如何理解作用域
自由变量:当前作用域没有定义的变量
当前作用域找不到的变量定义会往父级作用域找
作用域链——自由变量向上寻找的过程
2.5 实际开发中闭包的应用
- isFirstLoad 例子(判断一个值是否第一次出现)
- 闭包的作用
1、保护对象内的属性不被外部修改。
函数a中只有函数b才能访问,而无法通过其他途径访问到,因此保护了i的安全性。
2、在内存里维持某些变量。不会再f1调用后被自动清除。 - 什么是闭包
能够读取其他函数内部变量的函数,就是闭包。
闭包是将函数内部和函数外部连接起来的桥梁 - 闭包缺点
滥用闭包会造成内存泄露,因为闭包中引用到的包裹函数中定义的变量都永远不会被释放,
所以我们应该在必要的时候,及时释放这个闭包函数。 - 解决方法
obj = new Fname();
obj=null; //清空对象
clearInterval(timer) //清除计时器
dom.οnclick=null //指定为null
dom.addEventListener('click',fn,!1) //绑定方法
dom.removeEventListener('click',fn,!1) //尽量不要用匿名函数绑定,我们解绑事件时也好处理
dom.attachEvent ('onclick',fn); //绑定
dom.detachEvent('onclick',fn); //解除绑定