[JavaScript初级面试]4. JS基础-作用域和闭包

题目

  • this的不同使用场景,如何取值
  • 手写bind函数
  • 闭包在开发中的使用场景,举例说明
  • 创建10个<a>标签,点击的时候弹出对应的序号

作用域

全局作用域

函数作用域

块级作用域

代码块中{}

自由变量

产生:使用了一个在当前作用域没有定义的变量A
一个变量A在当前作用域没有定义,但被使用了;
这个变量A就是自由变量

确认自由变量的值,需要在当前作用域向上级作用域,一层一层寻找,直到找到为止;如果到了全局作用域,还没有找到,则报错xx is not defined
image
最内层的框中a,a1,a2都是自由变量

闭包

有两种情况:

  1. 函数作为函数参数
    image
  2. 函数作为函数返回值
    image

核心点:

  1. 因为函数拥有自己的作用域,使用函数的位置,如果与函数定义的位置不同,并且函数内部还存在自由变量, 则产生闭包(包住一个不属于当前作用域的变量)
  2. 作用域链形成时,函数作用域的父级作用域不是调用函数时所在的作用域,而是在定义函数时所在的作用域
  3. 在查找自由变量的值时,应该在函数定义所在的作用域为起始点查找;而不是在函数被调用的地方所在的作用域查找(沿着函数作用域链查找)

this

this的取值,不是在定义时确定的,而是在调用时确定的。(自由变量的值是在定义时确定的)

  • 构造函数中
    image
    创建空对象{},this变量;this变量指向空对象;给this添加属性(构造赋值过程);返回this
  • class
    image
  • bind, apply, call
func.call(this, arg1, arg2);
func.apply(this, [arg1, arg2])
func.bind(this) // bind 返回新函数

image

  • 普通函数
  • 箭头函数
    箭头函数中this永远绑定定义箭头函数时所在作用域的this。很直观
    image

解答

手写bind函数

函数实例的隐式原型就是Function的显式原型

Function.prototype.bind = function(){
  // 把参数拆解为数组
  const args = Array.prototype.slice.call(arguments)
  // 获取this,数组第一项; 在参数数组中剔除this
  const t = args.shift()
  // this 是 fn1.bind()里的fn1
  const self = this
  // bind会返回一个函数
  return function(){
    return self.apply(t, args)
  }
}

闭包应用举例

隐藏数据,只提供API

function createCache(){
  const data = {} //闭包中的自由变量,被隐藏,外界无法访问
  return {
    set: function(key, val){
      data[key] = val
    },
    get: function(key){
      return data[key]
    }
  }
}

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

方法一:

let a
for(let i=0; i<10; i++){
  a = document.createElement('a')
  a.innerHTML = i + '<br>'
  a.addEventListener('click', function(e){
    e.preventDefault()
    alert(i)
  })
  document.body.appendChild(a)
}

方法二:

let i, a
for(i=0; i<10; i++){
  a = document.createElement('a')
  a.innerHTML = i + '<br>'
  a.addEventListener('click', (e) => {
    e.preventDefault()
    alert(i)
  })
  document.body.appendChild(a)
}
posted @ 2021-09-03 17:45  Max力出奇迹  阅读(34)  评论(0编辑  收藏  举报
返回顶部↑