javascript面向对象之闭包
javascript面向对象之闭包
学习javascript一段时间了,自己对闭包作出如下总结,如有某点不妥,请君指出,不胜感激!
要理解闭包,首先必须理解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);//123

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

- 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));//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() );//11

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

- 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);//199

第二种写法

- 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)//101

javascript面向对象之闭包的更多相关文章
- 关于javascript面向对象之闭包
要理解闭包,首先必须理解Javascript特殊的变量作用域. 变量的作用域无非就是两种:全局变量和局部变量. Javascript语言的特殊之处,就在于函数内部可以直接读取全局变量,而在函数外部无法 ...
- JavaScript面向对象,闭包内存图,闭包和作用域
var i = 10; function test(){ var j; i=20; //未定义 function test(){ j='hello'; } console.log(test()); / ...
- JavaScript面向对象之闭包的理解
首先了解一下什么是闭包,闭包是一个函数,通常被称为闭包函数或者绑定函数,该函数运行在一个特殊的环境里,该环境定义了一些本地变量,当该函数被调用时,仍可以使用这些本地变量. 当一个函数在不位于它所处的环 ...
- JavaScript面向对象(三)——继承与闭包、JS实现继承的三种方式
前 言 JRedu 在之前的两篇博客中,我们详细探讨了JavaScript OOP中的各种知识点(JS OOP基础与JS 中This指向详解 . 成员属性.静态属性.原型属性与JS原型链).今天 ...
- JavaScript函数、闭包、原型、面向对象
JavaScript函数.闭包.原型.面向对象 断言 单元测试框架的核心是断言方法,通常叫assert(). 该方法通常接收一个值--需要断言的值,以及一个表示该断言目的的描述. 如果该值执行的结果为 ...
- javascript(面向对象,作用域,闭包,设计模式等)
javascript(面向对象,作用域,闭包,设计模式等) 1. 常用js类定义的方法有哪些? 参考答案:主要有构造函数原型和对象创建两种方法.原型法是通用老方法,对象创建是ES5推荐使用的方法.目前 ...
- 闭包初体验 -《JavaScript面向对象编程指南》
下面是我对闭包的理解:(把他们整理出来,整理的过程也是在梳理) 参考<JavaScript面向对象编程指南> 1.首先,在理解闭包之前: 我们首先应该清楚下作用域和作用域链 作用域:每个函 ...
- JavaScript学习笔记(三)——this、原型、javascript面向对象
一.this 在JavaScript中this表示:谁调用它,this就是谁. JavaScript是由对象组成的,一切皆为对象,万物皆为对象.this是一个动态的对象,根据调用的对象不同而发生变化, ...
- JavaScript学习总结(三)——this、原型、javascript面向对象
一.this 在JavaScript中this表示:谁调用它,this就是谁. JavaScript是由对象组成的,一切皆为对象,万物皆为对象.this是一个动态的对象,根据调用的对象不同而发生变化, ...
随机推荐
- IT行业,需要经常锻炼,开篇从本钱开始
今天下完班,和部门兄弟一起去打了两小时乒乓球,大汗淋漓,很痛快. 败给了两个高手,感觉年龄大了些,灵活性没有以前那么好了. 想想以前读书时,在整个学校都叱诧风云,如今即败给了几个老手,唉. 看来以后要 ...
- NET Platform Standard
NET Platform Standard 相关博文:ASP.NET 5 Target framework dnx451 and dnxcore50 .NET Platform Standard:ht ...
- mysql READ-COMMITTED 模式下 行锁不会升级到表级锁
mysql> select sn,id,info from s100 group by id; +-----+------+------+ | sn | id | info | +-----+- ...
- HDU 4981 Goffi and Median(水)
HDU 4981 Goffi and Median 思路:排序就能够得到中间数.然后总和和中间数*n比較一下就可以 代码: #include <cstdio> #include <c ...
- Linux目录结构和常用命令
源地址:http://www.cnblogs.com/JCSU/articles/2770249.html 一.Linux目录结构 你想知道为什么某些程序位于/bin下,或者/sbin,或者/usr/ ...
- jquery中怎么删除<ul>中的整个<li>包括节点
.$('ul li').remove(); .$('ul li').each(function(){ $(this).remove(); }); .$("ul").find(&qu ...
- html5实现拖拽文件上传
以下是自学it网--中级班上课笔记 网址:www.zixue.it html文件 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict ...
- 改动Oracle GoldenGate(ogg)各个进程的读检查点和写检查点
请注意:请谨慎改动Oracle GoldenGate(ogg)各个进程的读检查点和写检查点. 请确保已经 掌握 ogg 各个进程的读检查点和写检查点的详细含义. BEGIN {NOW | yyyy-m ...
- poj3461 Oulipo (KMP模板题~) 前面哪些也是模板题 O.O
# include <stdio.h> # include <algorithm> # include <string.h> using namespace std ...
- 关于PHP的内置服务器的使用
今天刚开始正式学习PHP(之前有一点了解),推荐学习的网站是w3school.一开始不知道tomcat服务器不支持PHP脚本,直接把.php文件放到tomcat里面去运行,结果嵌入的php代码段没有什 ...