Skip to content

一、作用域和闭包

1. this的不同应用场景,如何取值?

答案: this取什么样的值是在函数执行的时候决定的,不是在函数定义的时候决定的。
解析:

  • 作用域和自由变量

    • 作用域分为:全局作用域、函数作用域、块级作用域(ES6新增)。
      js
        if (true) {
          let a = 3
        }
      console.log(a) //报错,这称为块级作用域
    • 自由变量:
      • 一个变量在当前作用域没有定义,但被使用了。
      • 向上级作用域,一层一层依次寻找,直到找到为止。
      • 如果到全局作用域都没找到,则报错xx is not defined
  • 闭包

    • 闭包是作用域应用的特殊情况,有两种表现:一种是函数作为参数被传递;一种是函数作为返回值被返回。
    • 对于下述的两种情况:关键点在于,所有自由变量的查找,是在函数定义的地方,向上级作用域查找,不是在执行的地方!!
      js
          // 函数作为返回值
          function create() {
              let a = 100
              return function() {
                  console.log(a);
              }
          }
          
          const fn = create()
          a = 200
          fn() // 100
      js
          // 函数作为参数
          function print(fn) {
              let b = 200
              fn()
          }
          
          b = 100
          function fn() {
              console.log(b);
          }
          print(fn) // 100
  • this

注意:this取什么样的值是在函数执行的时候决定的,不是在函数定义的时候决定的。

  • 作为普通函数
  • 使用call、apply、bind
    js
      function fn1(){
        console.log(this);
      }
      fn1() // window
    
      fn1.call({ x: 200 }); // { x: 100 }
    
      const fn2 = fn1.bind({ x: 200 });
      fn2(); // { x: 200 }
  • 作为对象方法被调用
  • 在class方法中调用
  • 箭头函数
    js
      const zhangsan = {
        name: '张三',
        sayHi() {
          // this 即当前对象
          console.log(this);
        },
        wait() {
          setTimeout(() => {
            // this 即当前对象
            console.log(this);
          })
        }
      }
      zhangsan.sayHi()
      zhangsan.wait()

2. 手写bind函数

  • 第一步,将函数的参数从arguments这个伪数组转化成数组
  • 第二步,推出数组的第一项作为this对象
  • 第三步,用变量self指向调用bind1的参数
  • 最后,返回一个匿名函数,匿名函数的返回值使用调用apply
js
  // arguments对象是所有(非箭头)函数中都可用的局部变量。
  // 模拟bind
  Function.prototype.bind1 = function() {
    // 将arguments对象转化成数组
    // const args = Array.prototype.slice.call(arguments)
    const args = [...arguments]
  
    // 获取 this (数组第一项)
    const t = args.shift()
    //self指向调用bind1的函数
    const self = this
  
    // 返回一个函数
    return function() {
      return self.apply(t, args)
    }
  }
  
  // 测试
  function fn1(a, b, c) {
    console.log('this', this);
    console.log(a, b, c);
    return 'this is fn1'
  }
  
  const fn2 = fn1.bind1({x: 100}, 10, 20, 30)
  const res = fn2()
  console.log(res);

3. 实际开发中闭包的应用场景,举例说明

答案: 隐藏数据,只提供api

js
  // 闭包隐藏数据,只提供API
  function createCache() {
    const data = {}  //闭包中的数据,被隐藏,不被外界访问
    return {
      set(key, val) {
        data[key] = val
      },
      get(key) {
        return data[key]
      }
    }
  }
  
  const c = createCache()
  c.set('a', 100)
  console.log(c.get('a'));

Released under the MIT License.