一、this易错分析

在学习闭包的时候,有一个概念this很重要,关于this的理解,下面3种情况:this指向谁?

fn.call(obj1);
obj2.fn()
fn()

答案是obj1 obj2 window

判断this的指向有3条规则:

执行函数的过程中肯定存在两方,一方是调用函数的人caller,一方是被调用的人callee,callee永远是函数fn,caller遵循以下的规范:

  • fn.call(xxx) fn.apply(xxx)的时候,this永远指向xxx
  • ooo.fn()或者ooo['fn']()的时候,this永远指向ooo
  • fn()的时候this指向window

    所以针对上面代码:
  1. call/apply的作用是改变函数的调用者,或者说是改成this,改变this为 call /apply的第一个参数

  2. 一个函数没人调用的时候,相当于window调用了他

  3. 函数中除去this和arguments的其它变量,均遵守闭包规则,闭包的位置永远是函数定义的位置。

二、闭包易错代码分析

下面看两个代码实例,它们来源于阮一峰的文章闭包讲解。

 var name = "The Window";
  var object = {
    name : "My Object",
    getNameFunc : function(){
      return function(){
        return this.name;
      };
    }
  };
  alert(object.getNameFunc()());

返回结果是:

the window

分析:

alert(object.getNameFunc()());

这个里面有2个括号,要分析两次,把语句拆开:

第一步:var fn = object.getNameFunc();这时执行getNameFunc的时候,this是object,第一次return返回:function(){return this.name;}

第二步fn(),这时候函数由于没有调用者,根据规则3,函数的this ->window,这个函数里面的this.name实际上是window.name


 var name = "The Window";
  var object = {
    name : "My Object",
    getNameFunc : function(){
      var that = this;
      return function(){
        return that.name;
      };
    }
  };
  alert(object.getNameFunc());
返回结果:My Object

分析

同样分成两步执行:

第一步执行:var fn = object.getNameFunc();这个时候,this指向object,同时在函数执行的过程中,在getNameFunc所在的闭包内创建了变量that,that = this 所以that指向object,然后第二步执行fn(),这个时候由于没有作用对象,fn里面的this指向window,但是我们在这访问的是that.name,在fn里面没有找到叫that的东西,然后根据闭包规则找到fn的上一级闭包getNameFunc,我们发现在这有一个变量that,它指向object,所以that,name就是object.name,是my object

由此可见,闭包的概念更好理解了:

  1. 闭包就是函数的局部变量集合,只是这些局部变量在函数返回后会继续存在。
  2. 闭包就是就是函数的“堆栈”在函数返回后并不释放,我们也可以理解为这些函数堆栈并不在栈上分配而是在堆上分配
  3. 当在一个函数内定义另外一个函数就会产生闭包

简单来说,闭包就是在另一个作用域中保存了一份它从上一级函数或作用域取得的变量(键值对),而这些键值对是不会随上一级函数的执行完成而销毁。周爱民说得更清楚,闭包就是“属性表”,闭包就是一个数据块,闭包就是一个存放着“Name=Value”的对照表。就这么简单。但是,必须强调,闭包是一个运行期概念。有两个主要特点:

  • 作为一个函数变量的一个引用 - 当函数返回时,其处于激活状态。
  • 一个闭包就是当一个函数返回时,一个没有释放资源的栈区。

三、闭包的作用

  1. 可以读取函数内部的变量
  2. 让这些变量的值始终保持在内存中。

四、闭包的缺点

1)由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,在IE中可能导致内存泄露。解决方法是,在退出函数之前,将不使用的局部变量全部删除。

2)闭包会在父函数外部,改变父函数内部变量的值。所以,如果你把父函数当作对象(object)使用,把闭包当作它的公用方法(Public Method),把内部变量当作它的私有属性(private value),这时一定要小心,不要随便改变父函数内部变量的值。

参考资料:

学习Javascript闭包:http://www.ruanyifeng.com/blog/2009/08/learning_javascript_closures.html

javascript的闭包:http://www.cnblogs.com/rubylouvre/archive/2009/07/24/1530074.html

JavaScript 闭包深入理解:http://www.jb51.net/article/18303.htm

理解 Javascript 的闭包:http://www.oschina.net/question/28_41112

ife task0003学习笔记(三):JavaScript闭包的更多相关文章

  1. ife task0003学习笔记(一):JavaScript作用域

    在学习JavaScript作用域概念之前,首先要明白几个概念:执行环境.变量对象.作用域链. 一.JavaScript执行环境(execution context): 在<Professiona ...

  2. ife task0003学习笔记(五):JavaScript面向对象

    JavaScript 支持函数式编程.闭包.基于原型的继承等高级功能.在 Java 等面向对象的语言中,this 关键字的含义是明确且具体的,即指代当前对象.而在 JavaScript 中,this ...

  3. ife task0003学习笔记(四):JavaScript构造函数

    JavaScript创建对象主要是3种方法:工厂模式.构造函数模式.原型模式.其实对于构造函数的概念,我们并不陌生.在之前学习c++语言的时候,也有提到过构造函数的概念.除了创建对象,构造函数(con ...

  4. ife task0003学习笔记(二):JavaScript原型

    function aaa(){} aaa.prototype.bbb=function(){} var obj1=new aaa() var obj2=new aaa() obj1和obj2都有一个属 ...

  5. 【学习笔记】JavaScript的基础学习

    [学习笔记]JavaScript的基础学习 一 变量 1 变量命名规则 Camel 标记法 首字母是小写的,接下来的字母都以大写字符开头.例如: var myTestValue = 0, mySeco ...

  6. amazeui学习笔记三(你来我往1)--常见问题FAQs

    amazeui学习笔记三(你来我往1)--常见问题FAQs 一.总结 1.DOM事件失败:记得加上初始化代码,例如 图片轮播 $('#my-slider').flexslider(); 2.jquer ...

  7. Oracle学习笔记三 SQL命令

    SQL简介 SQL 支持下列类别的命令: 1.数据定义语言(DDL) 2.数据操纵语言(DML) 3.事务控制语言(TCL) 4.数据控制语言(DCL)  

  8. [Firefly引擎][学习笔记三][已完结]所需模块封装

    原地址:http://www.9miao.com/question-15-54671.html 学习笔记一传送门学习笔记二传送门 学习笔记三导读:        笔记三主要就是各个模块的封装了,这里贴 ...

  9. RX学习笔记:JavaScript数组操作

    RX学习笔记:JavaScript数组操作 2016-07-03 增删元素 unshift() 在数组开关添加元素 array.unshift("value"); array.un ...

随机推荐

  1. CSRF漏洞详细说明

    CSRF漏洞详细说明 通常情况下,有三种方法被广泛用来防御CSRF攻击:验证token,验证HTTP请求的Referer,还有验证XMLHttpRequests里的自定义header.鉴于种种原因,这 ...

  2. [.net 多线程]异步编程模式

    .NET中的异步编程 - EAP/APM 从.NET 4.5开始,支持的三种异步编程模式: 基于事件的异步编程设计模式 (EAP,Event-based Asynchronous Pattern) 异 ...

  3. C# WPF Webbrowser 强制所有网页链接在同一页面打开

    只要搞懂Winform的  WPF稍微改一改就可以了 主类:负责跳转的 using System; using System.Collections.Generic; using System.Com ...

  4. 看了这篇Dubbo RPC面试题,让天下没有难面的面试题!

      前言: RPC非常重要,很多人面试的时候都挂在了这个地方!你要是还不懂RPC是什么?他的基本原理是什么?你一定要把下边的内容记起来!好好研究一下!特别是文中给出的一张关于RPC的基本流程图,重点中 ...

  5. 为什么不应该重写service方法?

      故事通常是这样开始的: 从前,有一个程序猿,他语重心长地对孙子说:“孩子,要是你以后写servlet,最好不要重写service方法啊” 孙子大为不解,程序猿又说:“听爷爷的,准没错,爷爷的爷爷就 ...

  6. 【10.2.3】ArcGIS Runtime for Android搭建开发环境过程中问题具体解释

    一.Visual Studio Ultimate2012安装过程问题 1.问题描写叙述 安装完毕后,您将看到一条消息,指示安装程序已完毕.但并非全部的功能具有已正确安装.以及下面警告消息: Micro ...

  7. spring boot项目分享

    Spring boot项目分享 以下项目是我自己做的一些练习项目,有兴趣的小伙伴可以下载下来看下 1.员工管理系统 下载地址:我的github 后续会继续补充

  8. 题解 P3386 【【模板】二分图匹配】

    题目链接 首先呢声明一下,本宝宝发这篇题解只是为了(goto a;) 个人还是比较喜欢跑dinic暴力跑最大流...竟然比匈牙利还快..如果说不懂网络流的~~蒟蒻~~大佬们.可以看看这个(反正我就是在 ...

  9. TypeScript入门-类

    ▓▓▓▓▓▓ 大致介绍 在ECMASript6中引入了类这一概念,通过class声明一个类.对于学习过C和C++的人应该不会陌生 ▓▓▓▓▓▓ 类 看一个简单的类: class Greeter { g ...

  10. C++20草案中的宇宙飞船运算符(<=>,spaceship operator)

    C++20草案中的宇宙飞船运算符(<=>,spaceship operator) Herb Sutter提议的新三路运算符<=>已经被合入C++20草案中. 宇宙飞船运算符(h ...