几天没有更新,这两天使周末,给大家整理了一几篇东西,有关于作用域的,闭包的,还有递归的,闭包和递归,对于大部分初次接触编程的人来说还是有些难度的,昨天,花了一点时间给大家整理了一下,今天,给大家上传上来,让大家看看,部分属于个人观点,如有错误,欢迎指出
这一篇给大家讲讲什么是闭包,闭包在很多语言中都是有的,Java,C#等都是有的,这里给大家讲讲JS中的闭包
1. 闭包
闭包的含义就是闭合,抱起来。简单的的来说就是一个具有封闭功能与包裹功能的一个结构,所谓的闭包就是 有一个具有封闭的对外不公开的包裹结构,或空间
在JS中函数可以构成闭包,一般函数是一个代码结构的封闭结构,即包裹的特性,同事根据作用域规则 只允许函数访问外部的数据,外部无法访问函数内部的数据,即封闭的对外不公开的特性,因此说函数可以构成闭包
1.1. 闭包要解决什么问题
- 闭包不允许外界访问
- 要解决的问题就是间接访问该数据
函数就可以构成闭包,要解决的问题就是访问到函数内部的数据
function foo () {
var num = 123;
return num;
}
var res = foo();
console.log( res ); // => 123
- 这里的确是访问到函数中的数据
- 但是该数据不能第二次访问. 因为第二次访问的时候又要调用一次 foo, 表示又有一个新的 num = 123 出来了
在函数内的数据, 不能直接在函数外被访问, 那么再函数内如果定义一个函数, 那么再这个内部函数中是可以直接访问的
function foo() {
var num = Math.random();
function func() {
return num;
}
return func;
}
var f = foo();
// f 可以直接访问这个 num
var res1 = f();
var res2 = f();
练习:
function foo () {
var o = { name: 'jim' };
return function () {
return o;
}
}
1.2. 函数科里化(高阶函数)
定义一个函数, 该函数返回一个函数, 那么在调用的时候
function foo() {
function func() {
}
return func;
}
foo()()
JavaScript 模式
function color( r, g, b ) {
// ...
}
=>
color( 255, 0, 0 )
function color ( r ) {
return function color( g ) {
return color( b ) {
}
}
}
color( 255 )( 0 )( 0 )
1.3. 如何获得超过一个数据
function foo () {
var num1 = Math.random();
var num2 = Math.random();
return {
num1: function () {
return num1;
},
num2: function () {
return num2;
}
}
}
1.4. 如何完成读取一个数据和修改这个数据
function foo () {
var num = Math.random();
return {
get_num: function () {
return num;
},
set_num: function ( value ) {
num = value;
}
}
}
1.5. 基本的闭包结构
一般闭包的问题就是要想办法简介的获得函数内数据的使用权,那么我们可以总结出一个基本的使用模型
- 写一个函数,函数内定义一个新函数,返回新函数,用新函数获得函数内的数据
- 写一个函数,函数内定义一个对象,对象中绑定多个函数(方法),返回对象,利用对象的方法访问函数内的数据
1.6. 闭包的基本语法
闭包是为了实现 具有私有访问空间的 函数
- 带有私有访问数据的对象
function Person() {
this.name = '张三';
// setName( '' )
}
// 所谓的私有数据, 就是说只有函数内部可以访问的数据, 或对象内部的方法可以访问的数据
// 1 最简单的实现方式
function createPerson() {
var __name__ = "";
return {
get_Name: function () {
return __name__;
},
set_Name: function ( value ) {
// 如果不姓张就报错
if ( value.charAt( 0 ) === '张' ) {
__name__ = value;
} else {
throw new Error( '姓氏不对, 不能取名' );
}
}
};
}
// 2
-
带有私有数据的函数
var func = function () {} function func () {} var foo = (function () { // 私有数据 return function () { // 可以使用私有的数据 }; })();
1.7. 闭包的性能问题
函数执行需要内存,那么函数中定义的变量,会在函数执行结束后自动护手,凡是因为闭包结构,被引出的数据, 如果还有变量引用这些数据的话,那么这些数据就不会被回收。
因此在使用闭包的时候如果不使用某些数据了,一定要赋值一个 null
var f = (function () {
var num = 123;
return function () {
return num;
};
})();
// f 引用着函数, 函数引用变量 num
// 因此在不使用该数据的时候, 最好写上
f = null;
1.8. 闭包的练习
1.8.1. 对象模型
function foo() {
// 私有数据
return {
method: function ( ) {
// 操作私有数据
}
}
}
1.8.2. 函数模型
可以实现一个函数的二次加工
function foo () {
// 私有数据
return function () {
// 可以操作私有数据
}
}
var func = foo();
与下面这个正常的区别在于,自己有一个私有的数据
var fun = function () {
};
我们还将这种带有带有私有数据的函数模型称作带有缓存功能的函数
1.8.3. 沙箱模式(闭包应用的一个典范)
1.8.3.1. 沙箱的概念
沙盘与盒子,就可以在有一个小小的空间内模拟现实世界,特点是执行的效果与现实世界一模一样,但是只在沙箱中模拟与现实无关
1.8.3.2. 沙箱模式
沙箱模式就是在一个自调用的函数,代码写到函数中一样会执行,但是不会与外界有任何影响
例如在JQ中
(function () {
var jQuery = function () {
// 所有的算法
}
// ....
// ....
jQuery.each = function () {}
window.jQuery = window.$ = jQuery;
})();
$.each( ... )
1.8.4. 带有缓存功能的函数(这也是沙箱)
以 斐波那契 数列为例
var fib = (function () {
var data = [ 1, 1 ];
return function ( n ) {
var v = data[ n ];
if ( v === undefined ) {
v = fib( n-1 ) + fib( n-2 );
data[ n ] = v;
}
return v;
};
})();