作用域和闭包

111 阅读2分钟

作用域和闭包

作用域和自由变量

  • 全局作用域
  • 块级作用域
  • 函数作用域

自由变量

  • 一个变量在当前作用域没有定义,但是被使用
  • 向上一级作用域一层层依次寻找,直至找到为止
  • 直到全局作用域都没找到,则报错xx is not defined

this(在函数执行时定义)

作为普通函数

function fn1(){
  console.log(this)
}
fn1() //window

使用call apply bind

fn1.call({x: 100})  //{x: 100}
const fn2 = fn1.bind({x:200})
fn2()     //{x: 200}

作为对象方法被调用

  • 返回对象本身

在class方法中被调用

  • 返回实例本身

箭头函数

const zhangsan = {
  name: '张三'sayHi(){
    // this指向当前对象
    console.log(this)
  },
  wait(){
    setTimeout(function(){
      //this === window
      console.log(this)
    })
  },
  waitAgain(){    //箭头函数取上级作用域的值
    setTimeout(()=>{
      //this === 当前对象
      console.log(this)
    })
  }
}

手写bind

bind作用

function fn1(a, b, c) {
    console.log('this', this)
    console.log(a, b, c)
    return 'this is fn1'
}

const fn2 = fn1.bind({ x: 100 }, 10, 20, 30)
console.log(fn2())

//result
this { x: 100 }
10 20
this is fn1

手写

Function.prototype.bindHand = function(){
  // 拆解为数组
  const args = Array.prototype.slice.call(arguments)
  // 获取this
  const t = args.shift()
  // 原来的函数
  const self = this
  // 返回函数
  return function(){
    return self.apply(t, args)
  }
}

闭包

  • 一个函数和对其周围状态(词法环境)的引用捆绑在一起(或者说函数被引用包围),这样的组合就是闭包(closure)。也就是说,闭包让你可以在一个内层函数中访问到其外层函数的作用域。在 JavaScript 中,每当创建一个函数,闭包就会在函数创建的同时被创建出来。
  • 函数作为参数被传递
function print(fn){
  let a = 200
  fn()
}
let a = 100
function fn(){
  console.log(a)
}
print(fn)
  • 函数作为返回值被返回
function create(){
  let a = 100
  return function(){
    console.log(a)
  }
}
let fn = create()
let a = 200
fn()

实际开发中闭包的应用

  • 隐藏数据
  • 做一个简单的cache数据
function createCache(){
  const data = {}  //闭包中的隐藏数据,不能被外界访问
  return {
    set: function(key, val){
      data[key] = val
    },
    get: function(key){
      return data[key]
    }
  }
}

const c = createCache()
c.set(1, 2)
console.log(c.get(1)) //2