JavaScript 闭包

1.概念

1.1.对象

对象是属性的集合,一切(引用类型)都是对象,没有方法,方法也是属性。对象都是通过函数创建的。

javascript 中只有2种数据类型:
1.值类型:undefined, number, string, boolean
2.引用类型:除了值类型之外都是引用类型

1.2.函数

函数是由事件驱动的或者当它被调用时执行的可重复使用的代码块。

1.3.原型

每个函数都有一个prototype属性,每个对象都有一个__proto__属性,指向的是创建这个对象的函数的prototype 属性。

1.3.1.原型的作用

  1. 不使用prototype属性定义的对象方法,是静态方法,只能直接用类名进行调用!另外,此静态方法中无法使用this变量调用对象其他的属性
  2. 使用prototype属性定义的对象方法,是非静态方法,只有在实例化后才能使用!其方法内部可以this来引用对象自身中的其他属性

原型的灵活性:
Java和C#中,你可以简单的理解class是一个模子,对象就是被这个模子压出来的一批一批月饼(中秋节刚过完)。压个啥样,就得是个啥样,不能随便动,动一动就坏了。而在javascript中,就没有模子了,月饼被换成了面团,你可以捏成自己想要的样子

1.4.自由变量

A作用域中使用的变量x,却没有在A作用域中声明(即在其他作用域中声明的),对于A作用域来说,X就是一个自由变量

1.4.1.自由变量的取值方式

自由变量要到创建这个函数的那个作用域中取值——是**创建而不是调用**,切记切记。

1.5.闭包

Javascript允许使用内部函数,即函数定义和函数表达式位于另一个函数的函数体内。而且,这些内部函数可以访问它们所在的外部函数中声明的所有局部变量、参数和声明的其他内部函数。当其中一个这样的内部函数在包含它们的外部函数之外被调用时,就会形成闭包

2.对象和函数关系

2.1.对象是通过函数创建的

// Object是通过function定义的
function Object(value) {}
// 对象是通过 new Object()方式创建的
var obj = new Object()

2.2.而函数却又是一种对象

// 函数 Object定义如下
function Object(value) {}
// 实际上它是一种快捷方式,真正的实现方式是下面的方式,所以函数也是一种对象
var Object = new Function()

每个函数都有一个默认的prototype属性值,即原型每一个对象都有一个__proto__指向创建改对象函数的prototype,Object的prototype指向的是null。
访问一个对象的属性时,先在基本属性中查找,如果没有,再沿着__proto__这条链向上找,这就是原型链

3.闭包的写法

3.1.给函数添加一些属性

function Circle(r) {  
      this.r = r;  
}  
Circle.PI = 3.14159;  
Circle.prototype.area = function() {  
  return Circle.PI * this.r * this.r;  
}  
  
var c = new Circle(1.0);     
alert(c.area());   

3.2.将函数当做值赋给变量

var Circle = function() {  
   var obj = new Object();  
   obj.PI = 3.14159;  
     
   obj.area = function( r ) {  
       return this.PI * r * r;  
   }  
   return obj;  
}  
  
var c = new Circle();  
alert( c.area( 1.0 ) );  

3.3.new 一个对象,然后给对象添加属性和方法

var Circle = new Object();  
Circle.PI = 3.14159;  
Circle.Area = function( r ) {  
       return this.PI * r * r;  
}  
  
alert( Circle.Area( 1.0 ) );  

3.4.声明一个空的对象

var Circle={  
   "PI":3.14159,  
 "area":function(r){  
          return this.PI * r * r;  
        }  
};  
alert( Circle.area(1.0) ); 

3.5.使用Function方式创建

var Circle = new Function("this.PI = 3.14159;this.area = function( r ) {return r*r*this.PI;}");  
  
alert( (new Circle()).area(1.0) );  

总的来说,上面几种方法,第2中和第4中较为常见,大家可以根据习惯选择。

3.闭包的用途

3.1.匿名自执行函数

有的函数只需要执行一次,其内部变量无需维护,比如UI的初始化,那么我们可以使用闭包:

var data= {    
    table : [],    
    tree : {}    
};    
     
(function(dm){    
    for(var i = 0; i < dm.table.rows; i++){    
       var row = dm.table.rows[i];    
       for(var j = 0; j < row.cells; i++){    
           drawCell(i, j);    
       }    
    }    
       
})(data);   

3.2.结果缓存

我们开发中会碰到很多情况,设想我们有一个处理过程很耗时的函数对象,每次调用都会花费很长时间,那么我们就需要将计算出来的值存储起来,当调用这个函数的时候,首先在缓存中查找,如果找不到,则进行计算,然后更新缓存并返回值,如果找到了,直接返回查找到的值即可。闭包正是可以做到这一点,因为它不会释放外部的引用,从而函数内部的值可以得以保留,这样我们在第二次调用的时候,就会从缓存中读取到该对象。

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title></title>
</head>
<body>
<script src="js/jquery.js"></script>
<div id="id" class="id">缓存测试</div>
<script>
	// 生成给定key的value
    function getValue(id) {
        document.writeln('为:' + id + '创建值');
        document.writeln('<br>')
        document.writeln('<br>')
        return "value is "+ id;
    }

    var CacheSearchBox = (function () {
        var cache = {}, count = [];
        return {
            // 缓存中搜索方法
            search: function (searchId) {
                // 如果在缓存中,直接返回缓存中对象
                if(searchId in cache) {
                    document.writeln('从缓存中取数据');
                    document.writeln('<br>')
                   return cache[searchId];
                }
                document.writeln('缓存中无此数据');
                document.writeln('<br>')
                var value = getValue(searchId);
                cache[searchId] = value;
                count.push(searchId)
                // 保证缓存大小为2
                if(count.length > 2) {
                    document.writeln('缓存量超过最大值,删除最后一个元素');
                    document.writeln('<br>')
                    // count.pop() 删除并返回第一个元素
                    delete cache[count.shift()];
                }
                document.writeln('当前缓存对象内容:' + JSON.stringify(cache));
                document.writeln('<br>')
                document.writeln('当前缓存数组内容:' + JSON.stringify(count));
                document.writeln('<br>')
            },
            // 清除缓存方法
            clear: function (searchId) {
                if(searchId in cache) {
                    // 删除缓存中的对象
                    delete cache[searchId];
                    // 删除缓存数组中的数据
                    count.splice(count.indexOf(9), 1)
                    document.writeln('清除缓存对象:' + searchId);
                    document.writeln('<br>')
                    document.writeln('当前缓存对象内容:' + JSON.stringify(cache));
                    document.writeln('<br>')
                }
            }
        };
    })();

    CacheSearchBox.search('1');
    CacheSearchBox.search('1');
    CacheSearchBox.search('2');
    CacheSearchBox.search('2');
    CacheSearchBox.search('3');
    CacheSearchBox.clear('3')
</script>
</body>
</html>   

3.3.封装

var person = function(){    
    //变量作用域为函数内部,外部无法访问    
    var name = "default";       
       
    return {    
       getName : function(){    
           return name;    
       },    
       setName : function(newName){    
           name = newName;    
       }    
    }    
}();    
     
print(person.name);//直接访问,结果为undefined    
print(person.getName());    
person.setName("abruzzi");    
print(person.getName());    
   
得到结果如下:  
   
undefined  
default  
abruzzi  

3.4.实现类和继承

function Person(){    
    var name = "default";       
       
    return {    
       getName : function(){    
           return name;    
       },    
       setName : function(newName){    
           name = newName;    
       }    
    }    
    };   

    var p = new Person();
    p.setName("Tom");
    alert(p.getName());

    var Jack = function(){};
    //继承自Person
    Jack.prototype = new Person();
    //添加私有方法
    Jack.prototype.Say = function(){
        alert("Hello,my name is Jack");
    };
    var j = new Jack();
    j.setName("Jack");
    j.Say();
    alert(j.getName());
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值