前端面试基础必备JS学习笔记

JS闭包

2018-08-16  本文已影响0人  puxiaotaoc

一、变量的作用域

// 函数内部可以直接读取全局变量
    var n = 1;
    function fun1(){
      alert(n);
    }
    fun1(); // 1
// 函数外部无法读取函数内的局部变量
    function fun1(){
      var n = 1;
      alert(n);
    }
    alert(n); // n is not defined
// 函数内部声明变量的时候一定要使用var,否则实际上相当于声明了一个全局变量
    function fun1(){
      n = 1;
    }
    fun1();
    alert(n); // 1

二、闭包的引入

(function(a){
      console.log(a) // 3
 }(3))
// 在函数外部访问内部变量n
    function fun1() {
      var n = 1;
      return function() {      
        alert(n);    
      }
    }
    var result = fun1();
    result(); // 1
// getNameFunc的第一个()是属于方法调用,所以this绑定到了object对象,自然this.name为"My Object",但是闭包函数无法访问这个this,它只能访问到全局的this
// 当一个函数作为函数而不是方法调用的时候,这个this关键字引用全局对象
var name = "The Window"; 
    var object = {    
      name: "My Object",
      getNameFunc: function() {      
        return function() {        
          return this.name;      
        };    
      }  
    };  
    alert(object.getNameFunc()()); // The Window
// 并非闭包,并非一个函数内部的函数
var name = "The Window";  
    var object = {    
      name: "My Object",
      getNameFunc: function() {              
          return this.name; // My Object
          // return name; // The Window    
      }  
    };  
    alert(object.name); // My Object
    alert(object.getNameFunc());
var name = "The Window";  
    var object = {    
      name: "My Object",
      getNameFunc: function() {
        var _this = this;              
        return function() {
          return _this.name;     
        } 
      } 
    };  
    alert(object.name); // My Object
    alert(object.getNameFunc()()); // My Object
// 实现封装
// person之外的地方无法访问person内部的变量,只能通过提供闭包的形式来访问
var person = function() {    
      var name = "My Object";
      return {
        getName: function() {
          return name;
        },
        setName: function(val) {
          name = val;
        }
      }
    }
    var person1 = new person(); 
    alert(person1.name); // undefined
    alert(person1.getName()); // My Object
    person1.setName('lili');
    alert(person1.getName()); // lili
// 设置缓存
function db() {
      var data = {};
      return function(key, val) {
        if (val === undefined) {
          return data[key];
        } else {
          return data[key] = val;
        }
      }
    }
    var db = new db();
    console.log(db('x')); // undefined
    console.log(db('x',1)); // 1
    console.log(db('x')); // 1
// 使用自执行函数设置缓存
var db = (function() {
      var data = {};
      return function(key, val) {
        if (val === undefined) {
          return data[key];
        } else {
          return data[key] = val;
        }
      }
    })()
    console.log(db('x')); // undefined
    console.log(db('x',1)); // 1
    console.log(db('x')); // 1
// 代码中的result实际上就是闭包fun2函数,result一共运行了两次,第一次的值是1,第二次是2,函数fun1的局部变量n一直保存在内存中,并没有在fun1调用后被自动清除,
// 因为fun1是fun2的父函数,而fun2被赋值给了一个全局变量,这导致fun2始终在内存中,而fun2的存在依赖于fun1,因此fun1也始终在内存中,不会在调用结束后被垃圾回收机制回收
// nAdd=function(){n+=1},因为没有在nAdd前面使用var关键字,所以nAdd是一个全局变量,而不是局部变量
// 其次,nAdd的值是一个匿名函数,而这个匿名函数本身也是一个闭包,所以nAdd相当于一个setter,可以在函数外部对函数内部的局部变量进行操作
    function fun1() {
      var n = 1;
      nAdd = function() {
        n += 1;
      }
      return function fun2() {      
        alert(n);    
      }
    }
    var result = fun1();
    result(); // 1
    nAdd();
    result(); // 2

三、闭包的缺陷

上一篇下一篇

猜你喜欢

热点阅读