Skip to content

JS面试思考:4作用域闭包执行上下文

从题目入手、思考,寻找知识点最后解答

  • 说一下对变量提升的理解
  • 说明this几种不同的使用场景
  • 创建10个<a>标签,点击时弹出对应的序号
  • 如何理解作用域
  • 实际开发中闭包的应用

知识点

执行上下文

js
console.log(a) // undefined
var a = 100
fn('zhangsan') // 'zhangsan' 20
function fn(name) {
  age = 20
  console.log(name, age)
  var age
}

范围:一段<script>或者一个函数 全局:变量定义、函数声明 函数:变量定义、函数声明、this、arguments

this

要在执行时才能确认值,定义时无法确认

js
var a = {
  name: 'A',
  fn: function() {
    console.log(this.name)
  }
}
a.fn()  // 'A'  this === a
a.fn.call({name: 'B'})  // this === {name: 'B'}
var fn1 = a.fn
fn1() // undefined  this === window
  • 作为构造函数执行
  • 作为普通属性执行
  • 作为普通函数执行
  • call apply bind
  • es6箭头函数

作用域

es5及以前是没有块级作用域的(所以我们一般用IIFE来模拟)

作用域链

js
/* 例1 */
var a = 100
function fn() {
  var b = 200
  // 当前作用域没有定义的变量,即“自由变量”
  console.log(a)
  console.log(b)
}
fn()
/* 例2 */
var a = 100
function f1() {
  function f2() {
    var c = 300
    console.log(a) // a是自由变量
    console.log(b) // b是自由变量
    console.log(c)
  }
  f2()
}
f1()

作用域链就是 … (我理解的)这层作用域找不到的向父级找,父级找不到继续往上直到顶层作用域(window或global)

闭包

闭包的使用场景:

  • 函数作为返回值
  • 函数作为参数传递
js
/* 1 函数作为返回值 */
function f1() {
  var a = 100
  // 返回一个函数,函数作为返回值
  return function() {
    console.log(a) // 自由变量,父作用域寻找
  }
}
// f1得到一个函数
var f2 = f1()
var a = 200
f1() // 100
/* 2 函数作为参数传递 */
function Fn1() {
  var a = 100
  return function() {
    console.log(a) // 自由变量,父作用域寻找
  }
}
var fn1 = Fn1()
function Fn2(fn) {
  var a = 200
  fn()
}
Fn2(f1) // 100

解题

  • 说一下对变量提升的理解 - 见上文

  • 说明this几种不同的使用场景 - 见上文

  • 创建10个<a>标签,点击时弹出对应的序号

js
for (var i = 0; i < 10; i++) {
  (function(i) {
    var el = document.createElement('a');
    el.innerHTML = i + '<br>';
    el.addEventListener('click', function(e) {
      e.preventDefault()
      console.log(i)
    })
    document.body.appendChild(el);
  })(i)
}
  • 如何理解作用域

自由变量、作用域链(自由变量查找机制)、闭包的使用场景

  • 实际开发中闭包的应用
js
// 闭包实际应用中主要用于封装变量,收敛权限
function isFirstLoad() {
  // _作为私有变量、方法的前缀,这算是一个约定
  var _list = []
  return function(id) {
    if (_list.indexOf(id) >= 0) {
      return false
    } else {
      _list.push(id)
      return true
    }
  }
}
// 使用
var firstLoad = isFirstLoad()
firstLoad(10) // true
firstLoad(10) // false
firstLoad(20) // true

共 20 个模块,1301 篇 Markdown 文档。