要理解闭包,首先必须理解Javascript特殊的变量作用域。

变量的作用域无非就是两种:全局变量和局部变量。

Javascript语言的特殊之处,就在于函数内部可以直接读取全局变量,而在函数外部无法读取函数内的局部变量。

注意点,函数内部声明变量的时候,一定要使用var命令。否则变为全局变量。

简而言之,闭包就是一个受到保护的变量空间。

闭包案例

functon(){
var num = Math.random;
return num; }
var res = foo();
在这不能直接访问函数内部变量num,只可以间接访问 var r1 = foo();
var r2 = foo();
alert(r1 + '\n'+ r2);
如果使用return返回函数内的数据,理论上不是访问一个数据,
因为在函数运行会分配内存空间,函数调用的时候,数据也会再次创建

若要解决以上问题,获得相同的数据如何操作

function (){
var num = Math.random();
return function (){ return num;
} } var fn = foo();//函数调用一次num就是唯一的
var r1 = fn();
var r2 = fn();
alert(r1 + '\n' +r2)
//fn是在一个在函数内定义的函数,那么在执行时候可以访问到上一级作用域中的num ,
因此在最外面,就可以间接访问唯一的num。此处就是用到了闭包,此次起到保护数据的作用

函数的本质:Function的实例,也是对象。

执行一个函数,让函数返回对象

function Foo(){
var o = {num: 123};
return o;
}
var obj = Foo();
alert(obj.num);//123

在调用函数时,函数内部创建一个对象

o中存储着对象的引用,return是将o中的数据拷贝一份再返回

返回的结果被obj接收,此时obj存储的是对象的引用

执行一个函数,让函数返回一个函数

function Foo(){
var o = new Function('alert(123)');
return o;
}
var fn = Foo();
相当于var fn = new Functon('alert(123)');
alert(fn);//

执行一个函数,让函数返回一个数组

function func(){
var m = Math.random();
var n = Math.random();
return [
function () { return m;}
function () { return n;} ]
}
// var fns = func();
// var m1 = fns[0]();
// var n1 = fns[1]();
// alert(m1 +','+ n1) ; // var m2 = fns[0]();
// var n2 = fns[1]();
// alert(m2 +','+ n2) ;

在以上两组数据中输出的结果是相同的,

数组的优点体现出数据的有序性 多个数据可以进行排序

但是在复杂数据中,数据的序号就不再有优势

可以用对象对以上函数改进

function func(){
var m = Math.random();
var n = Math.random();
return {
get_M: function (){ return m;},
get_N: function (){ return n;}
};
}
// var obj = func();
// var m1 =obj.get_M();
// var n1 = obj.get_N();
// alert(m1 +','+ n1) ;

闭包案例之调用一函数提供两个方法,对num进行赋值和读取
第一种写法

function Foo(){
var obj = new Object(); //这里也可以写成 var obj = {};??
var num;
obj.get_num = function(){
return num;
};
obj.set_num = function(v){
num = v; };
return obj; }
var o = Foo();
console.log(o.get_num());//undefined
console.log(o.set_num(11));//undefined
console.log(o.get_num(11));//

第二种写法

function Foo() {
var num;
return {
get_num: function () {
return num;
},
set_num: function ( v ) {
num = v;
}
};
}
var o = Foo();
console.log( o.get_num() ); //undefined
console.log(o.set_num( 11 ));//undefined
console.log( o.get_num() );//

这有一个对以上函数的变式

function Foo() {
var num;
return {
_num: num,//赋值操作
set_num: function ( v ) {
num = v;
}
};
}
//相当于下面函数
function Foo() {
var num;
var obj = {};
obj._num = num;//上面声明的num和此时的_num变量是不同的
obj.set_num = function ( v ) {
num = v;
};
return obj;
} var o = Foo();
console.log( o._num );  //undefined
console.log(o.set_num(11)); //undefined
console.log(o._num); //undefined 取不出数据

闭包的应用:实现私有数据和缓存数据

闭包案例之斐波那契数列

没使用闭包的函数式

var count = 0;
var fib = function (n){
count++;
if(n< 0)throw new Error('不允许出现负数');
if(n === 0||n === 1)return 1;
// return fib(n-1)+fib(n-2);
return arguments.callee(n-1) + arguments.callee(n-2);
} console.log(fib(16));
console.log(count);
//分别计算第1、2、4、8、16、32项对应的次数为1、3、9、67、3193、7049155

从以上计算的次数可以看出性能的损耗很严重,那么闭包可以在此解决的问题是已经运算过得数据缓存下来

var count = 0;
var fib = (function(){
var arr = [];
return function (n){
count++;
if(n < 0)throw new Error('不允许出现负数');
var res = arr[n];//缓存数据 判断有无数据
if(res !== undefined){
return res;
}
else {
if(n === 0||n ===1) {
res = 1;
}
else{
res = fib(n - 1)+fib(n - 2);
}
}
arr[n] = res;
return res;
}
})();
console.log(fib(100));
console.log(count);//

第二种写法

var count = 0;
var fib = (function(){
var arr = [];
return function(n){
count++;
return feibo(arr,n);
}
})();
function feibo(arr,n){
if(n < 0)throw new Error("不允许出现负数");
var res = arr[n];
if(res != undefined){
return res;
}else{
if(n === 0 ||n === 1){
res = 1;
}else{
res = fib(n - 1) + fib(n - 2);
}
}
arr[n] = res;
return res;
}
console.log(fib(100));
console.log(count);

从上式可以看出闭包带来的好处;

拓展:谈到数据缓存也可以不用闭包,下面函数则与闭包无关

var fib = function ( n ) {
var res = fib[ n ]; // 先到函数名中取
if ( res !== undefined ) {
return res;
} else {
// 如果是 1 或 0 则将 1 返回给 res
// 否则递归结果交给 res; if ( n === 0 || n === 1 ) {
res = 1;
} else {
res = arguments.callee( n - 1 ) +
arguments.callee( n - 2 );
} fib[ n ] = res;
// 将计算的结果放到数组中, 那么下一次再计算的
// 时候可以直接拿来用, 就不用重新计算
fib.len++;//每次赋值完后
return res;
}
};
fib.len = 0;//给函数添加一个属性
console.log(fib(100));
console.log(fib.len)//

本人文笔有限,才疏学浅,文中若有不正之处,万望告知,不胜感激!

关于javascript面向对象之闭包的更多相关文章

  1. javascript面向对象之闭包

    javascript面向对象之闭包 学习javascript一段时间了,自己对闭包作出如下总结,如有某点不妥,请君指出,不胜感激! 要理解闭包,首先必须理解Javascript特殊的变量作用域. 变量 ...

  2. JavaScript面向对象,闭包内存图,闭包和作用域

    var i = 10; function test(){ var j; i=20; //未定义 function test(){ j='hello'; } console.log(test()); / ...

  3. JavaScript面向对象之闭包的理解

    首先了解一下什么是闭包,闭包是一个函数,通常被称为闭包函数或者绑定函数,该函数运行在一个特殊的环境里,该环境定义了一些本地变量,当该函数被调用时,仍可以使用这些本地变量. 当一个函数在不位于它所处的环 ...

  4. JavaScript面向对象(三)——继承与闭包、JS实现继承的三种方式

      前  言 JRedu 在之前的两篇博客中,我们详细探讨了JavaScript OOP中的各种知识点(JS OOP基础与JS 中This指向详解 . 成员属性.静态属性.原型属性与JS原型链).今天 ...

  5. JavaScript函数、闭包、原型、面向对象

    JavaScript函数.闭包.原型.面向对象 断言 单元测试框架的核心是断言方法,通常叫assert(). 该方法通常接收一个值--需要断言的值,以及一个表示该断言目的的描述. 如果该值执行的结果为 ...

  6. javascript(面向对象,作用域,闭包,设计模式等)

    javascript(面向对象,作用域,闭包,设计模式等) 1. 常用js类定义的方法有哪些? 参考答案:主要有构造函数原型和对象创建两种方法.原型法是通用老方法,对象创建是ES5推荐使用的方法.目前 ...

  7. 闭包初体验 -《JavaScript面向对象编程指南》

    下面是我对闭包的理解:(把他们整理出来,整理的过程也是在梳理) 参考<JavaScript面向对象编程指南> 1.首先,在理解闭包之前: 我们首先应该清楚下作用域和作用域链 作用域:每个函 ...

  8. JavaScript学习笔记(三)——this、原型、javascript面向对象

    一.this 在JavaScript中this表示:谁调用它,this就是谁. JavaScript是由对象组成的,一切皆为对象,万物皆为对象.this是一个动态的对象,根据调用的对象不同而发生变化, ...

  9. JavaScript学习总结(三)——this、原型、javascript面向对象

    一.this 在JavaScript中this表示:谁调用它,this就是谁. JavaScript是由对象组成的,一切皆为对象,万物皆为对象.this是一个动态的对象,根据调用的对象不同而发生变化, ...

随机推荐

  1. JS中的prototype属性

    JavaScript是基于对象的,任何元素都可以看成对象.然而,类型和对象是不同的.本文中,我们除了讨论类型和对象的一些特点之外,更重要的 是研究  如何写出好的并且利于重用的类型.毕竟,JavaSc ...

  2. QCA4002/QCA4004 为主流家电和消费电子产品推出低功耗Wi-Fi平台

    美国高通公司日前宣布,其子公司高通创锐讯推出全新芯片系列,这是低功耗Wi-Fi解决方案系列的一部分,可连接组成物联网的各种设备.QCA4002和QCA4004网络平台在芯片上纳入IP堆栈及完整的网络服 ...

  3. JavaEE Tutorials (16) - Java消息服务概念

    16.1JMS API概述198 16.1.1什么是消息传送198 16.1.2什么是JMS API199 16.1.3何时使用JMS API199 16.1.4Java EE平台如何使用JMS AP ...

  4. JSON 解析器。JSON.stringify和JSON.parse

    以前用的是JavaScript  的eval. 现在JSON 提供了JSON.stringify和JSON.parse两个函数. JSON.parse用于从一个字符串中解析出json对象. JSON. ...

  5. Puppet的执行过程

    图1 Puppet工作流程 1. 客户端Puppetd向Master发起认证请求,或使用带签名的证书. 2. Master告诉Client你是合法的. 3. 客户端Puppetd调用Facter,Fa ...

  6. openStack images概念及维护

    更改以创建镜像的属性 glance image-update img-uuid --property architecture=arm --propertyhypervisor_type=qemu C ...

  7. AS3事件机制概述

    事件机制是AS3的核心功能之一,没有充分掌握事件机制的方方面面,就不能算是精通AS3语言. 1. AS3事件机制的主要成员 IEventDispatcher:事件派发对象接口,定义了添加.派发.移除. ...

  8. 关于Apacheserver的訪问控制

    Apache的訪问控制指对不论什么资源的不论什么方式的訪问控制. 一.基于主机或者IP地址的控制 这样的訪问控制基于訪问者的主机名或者IP地址,通过使用 Deny 和 Allow 指令.实现同意或者禁 ...

  9. 关于cell中添加子视图 复用重叠问题的解决方法

    问题本质:   因为你要添加的子视图并不是在自定义的cell中实现的,而是根据系统给的UITableViewCell这个类创建的实例,每次进图 cellForRow方法都会创建一个cell,每次都要创 ...

  10. ubuntu14.04+xfce下启用fcitx,使用中文输入法

    1. 安装fcitx  sudo apt-get install fcitx-pinyin 2.启用fcitx 打开 setting -> Language Support -> Lang ...