Skip to content
On this page

作用域和闭包

作用域和自由变量

  • 作用域

    • 全局作用域

    • 函数作用域

    • 块级作用域(es6新增) if/for/while...中的{}

  • 自由变量

    • 一个变量在当前的作用域没有定义,但被使用了
    • 向上级作用域查找,知道找到为止
    • 如果直到全局作用域都没有找到,则报错 xxx is not defined

闭包

  • 什么是闭包?

    • 作用域应用的特殊情况,有两种表现:

      • 函数作为参数被传递
      • 函数作为返回值被传递
    • js
      // 函数作为返回值
      function create() {
        const a = 100;
        return function () {
          console.log(a);
        };
      }
      const a = 200;
      let fun1 = create();
      fun1();
      
      // 函数作为参数
      function print(fun) {
        const b = 200;
        fun();
      }
      const b = 100;
      function fun2(){
        console.log(b);
      }
      print(fun2)
      
      • 答案都为100
      • 结论:所有的自由变量的查找,是先在函数定义的地方,再向上级查找,不是在执行的地方!bi
  • 闭包的应用

    • 隐藏数据,封装私有变量
    • 制作工具, 如防抖节流,结果缓存等等
    • 绑定函数上下文,如bind
  • 闭包的优点

    • 包含函数内变量的安全,防止变量流入其他环境发生命名冲突,造成环境污染
    • 在适当的时候,可以在内存中维护变量并缓存,提高执行效率。
  • 闭包的缺点

    • 增加了内存消耗量,影响网页性能可能出现问题,过度的使用闭包可能会导致内存泄漏

this

this取什么样的值是在函数执行的时候确定的,不是在定义的时候确定的

  • 作为普通函数

    • js
      function fun1() {
        console.log(this);
      }
      fun1(); //window or global
      
  • 使用call apply bind

    • 关于三者的异同点文章

    • js
      fun1.call({ x: 100 }); //{ x: 100 }
      // bind返回一个函数,稍后调用才会执行,call和apply则是立即调用
      const fun2 = fun1.bind({ x: 200 });
      fun2(); //{ x: 200 }
      
  • 作为对象方法被调用

    • js
      const zhangsan = {
        name: "张三",
        sayHi(){
          // this 指向当前对象
          console.log(this);
        },
        wait(){
          setTimeout(function(){
            // this === window
            console.log(this);
          })
        },
        waitAgain(){
          setTimeout(()=>{
            // this 再次指向当前对象,因为箭头函数取上级作用域的this
            console.log(this);
          })
        }
      };
      
  • 在class方法中调用

    • js
      class People{
        constructor(name){
          this.name = name
        }
        sayHi(){
          console.log(this);
        }
      }
      const lisi = new People('李四')
      lisi.sayHi()  // lisi 对象
      
  • 箭头函数

    • 箭头函数本身没有,取上级作用域的this
  • 手写bind函数

    • js
      // 模拟bind
      Function.prototype.bind2 = function(self,...args){
        // 此处的this为执行bind2的Function
        const context = this
        return function(){
          return context.apply(self,args)
        }
      }