作用域&闭包
题目(答案见每题下方空白处)
1.说一下对变量提升的理解
变量提升即JS的预解析,也就是var声明的变量以及function开头的函数声明会在预解析时被提到整段代码的最前面,变量赋值为undefined,函数则直接为本体
而函数中的预解析还包括arguments(形参)和this指向,arguments也会被初始化赋值为undefined
2.说明this几种不同的使用场景
构造函数、对象属性、普通函数、call/apply/bind
3.创建10个a标签,点击每一个弹出对应的序号
(用闭包/let写)
4.如何理解作用域
(关键点:自由变量、作用域链、闭包的两个场景)
5.实际开发中闭包的使用
闭包可以用来收敛权限
知识点
执行上下文(预解析)
执行上下文(预解析)针对一段script/一个函数
全局中,提前拿出变量定义和函数声明,给变量初始化为undefined,函数则直接把函数本体丢到最前面
函数中提前拿出变量定义、函数声明、this和arguments,同样给变量初始化为undefined,函数也直接把本体丢到最前面去,this和arguments在函数执行前也都确定了值
this
this只有在执行时才能确认值,而定义的时候无法确认
this可以使用在构造函数、对象属性、普通函数、call、apply、bind方法中
构造函数中的this,当实例化一个对象时,构造函数中的this指向这个构造函数本身,而如果直接调用构造函数,则this指向window
对象的属性中,this指向该对象
普通函数中,this指向当前环境(window)
call、apply和bind方法中,this指向第一个传入的参数
作用域
两个最基础的点
1.JS中没有块级作用域(ES6的let和const添加了块级作用域)
2.只有全局作用域和函数作用域
块级作用域
ES6中新增的一个特性,对let和const声明的变量,只在其声明的块级作用域中生效
例如下方的两个for语句,var声明的会在循环结束后仍可以访问循环体中的变量,而let声明的则不可以访问
作用域链
在当前作用域未定义的变量称之为自由变量
对于函数体内部的变量,如果在其函数作用域中未定义,则会往其父级作用域查找是否有定义,有则调用,否则继续往上,直至全级作用域
闭包
闭包是用来访问函数作用域中的局部变量的
具体使用场景有二:
1.函数作为返回值
这里返回100是因为f1返回的匿名函数定义的位置在f1中,而f1中的a的值为100,外部的a是全局作用域的,跟匿名函数无关
2.函数作为参数传递
这里返回100是因为f1中的匿名函数定义在f1里,能访问到的是其定义时所处环境的a,所以为100
十个li标签的弹出问题
1.可以用闭包(自执行匿名函数)解决
2.可以用let的块级作用域特性解决
实际开发中的应用
闭包的特点在于,可以访问到函数作用域内部的局部变量,而局部变量是无法在外部修改的(除非提供API)
因此可以利用这一特性,限制权限
这里的list是函数的局部变量,不可以被修改,而函数只能用来记录某个数据是否出现过