语句

JavaScript是解释型语言,解释器是按照顺序逐句执行的(除了进行一些少量预处理,如将函数声明提前)。

顺序是由流程控制语句来控制的,常用的流程控制语句包括:

  • 条件控制语句:if...else和switch...case语句
  • 循环控制语句:while...、do...while、for和for-in语句
  • 其他:break、continue和try...catch语句

代码中除去流程控制语句,剩下的部分只做两件事:

  • 为变量赋值(声明新变量并复制如var obj = {word: "hello"},或为已有变量赋值x=y)
  • 调用函数,比如console.log("hello world")

实际上为了完成以上两件事,代码还需要编写值或对象的字面量,以及访问现有变量,但是单独这样做没有意义。

函数执行过程

上面说到,除去流程控制,代码只做两件事,为变量赋值和调用函数。前者不难理解,现在来看调用函数后发生了什么:

当解释器调用一个函数之后,就会创建与之对应的变量对象(注意,一个变量对象与一次函数调用对应,而不是与一个函数对应),函数内声明的所有局部变量都绑定在这个变量对象上,函数执行完毕后,不出意外,该变量对象就会销毁。

我们将函数执行过程中所有可以访问到的变量的集合称为函数的执行上下文。对C++来说,函数的执行上下文只有函数内部定义的变量、函数实参和全局变量,而JavaScript的最大特点在于,函数的执行上下文包括了函数调用者的执行上下文,也就是说在函数内部可以毫无障碍地访问函数外部的数据。在我们什么都没做的时候,其实已经处在了全局的执行上下文之中了。

var names = [];
function sayhi(name){
if(!names[name]){
names.push(name);
}
console.log("hello "+name);
}
sayhi("Ross");
sayhi("Rachel");
console.log(names); //-> ["Ross", "Rachel"]
console.log(name); //-> undefined

上面函数sayhi执行过程中,代码试图访问names变量,但是在函数内部并未定义names(GCC这时就要报错了),所以函数就去sayhi的调用者(window)的变量对象上找到了names。

当函数内部调用其他函数(或自己)时,变量对象就变成了三个或者更多,当在函数内试图访问某个变量时,就会从内向外依次在变量对象中查找变量,直到找到第一个变量为止。

闭包

上文说到,函数执行完毕后,不出意外,该变量对象就会销毁。实际上,经常会出现意外。如果函数执行完毕后,仍然有可能访问到函数内部的变量,此时虽然执行流程已经在函数外部了,但函数的变量对象不会被销毁

var last;
function sayhi(name){
last = function(){
return name;
}
console.log("hello "+name);
}
sayhi("Ross");
console.log(last()); //-> "Ross"

由于在sayhi函数内部,我们将外部变量last赋值为了一个新的函数,该函数返回sayhi函数的实参name,所以sayhi("Ross")之后,虽然sayhi已经执行完成了,但是last仍然可以访问到sayhi内部的变量name,所以由sayhi("Ross")这次调用带来的变量对象不会被销毁。而且,只要接下来的代码(解释器永远不知道下一行代码是什么)有可能访问到该变量对象中的元素,该变量对象就不会销毁。

变量对象未销毁,其包含的所有元素(包括那些不可能再被访问到的元素)也会保留。所以,如果使用不当,闭包会超出预期限度地加重浏览器的负担。(现在已有一些浏览器如Chrome开始尝试回收闭包中的那些不可能再被访问到的元素)。

闭包可以用来模拟对象的私有变量。下面这个对象对象chandler模拟了C++中的类的实例,两个属性name和hobby只能通过方法访问,不能被改变。

var chandler = (function(){
var name = "CHANDLER";var hobby = "joke";return {
getName : function(){return name;},
getHobby : function(){return hobby;}
}
})();

JavaScript备忘录(2)——闭包的更多相关文章

  1. 深入理解javascript原型和闭包 (转)

    该教程绕开了javascript的一些基本的语法知识,直接讲解javascript中最难理解的两个部分,也是和其他主流面向对象语言区别最大的两个部分--原型和闭包,当然,肯定少不了原型链和作用域链.帮 ...

  2. JavaScript葵花宝典之闭包

    闭包,写过JS脚本的人对这个词一定不陌生,都说闭包是JS中最奇幻的一个知识点,  虽然在工作中,项目里经常都会用到~  但是是不是你已经真正的对它足够的了解~~ 又或者是你代码中出现的闭包,并不是你刻 ...

  3. 深入理解javascript原型和闭包系列

    从下面目录中可以看到,本系列有16篇文章,外加两篇后补的,一共18篇文章.写了半个月,从9月17号开始写的.每篇文章更新时,读者的反馈还是可以的,虽然不至于上头条,但是也算是中规中矩,有看的人,也有评 ...

  4. 让你分分钟学会Javascript中的闭包

    Javascript中的闭包 前面的话: 闭包,是 javascript 中重要的一个概念,对于初学者来讲,闭包是一个特别抽象的概念,特别是ECMA规范给的定义,如果没有实战经验,你很难从定义去理解它 ...

  5. 深入理解javascript原型和闭包(1)——一切都是对象

    “一切都是对象”这句话的重点在于如何去理解“对象”这个概念. ——当然,也不是所有的都是对象,值类型就不是对象. 首先咱们还是先看看javascript中一个常用的函数——typeof().typeo ...

  6. 深入理解javascript原型和闭包(2)——函数和对象的关系

    上文(理解javascript原型和作用域系列(1)——一切都是对象)已经提到,函数就是对象的一种,因为通过instanceof函数可以判断. var fn = function () { }; co ...

  7. 深入理解javascript原型和闭包(3)——prototype原型

    既typeof之后的另一位老朋友! prototype也是我们的老朋友,即使不了解的人,也应该都听过它的大名.如果它还是您的新朋友,我估计您也是javascript的新朋友. 在咱们的第一节(深入理解 ...

  8. 深入理解javascript原型和闭包(4)——隐式原型

    注意:本文不是javascript基础教程,如果你没有接触过原型的基本知识,应该先去了解一下,推荐看<javascript高级程序设计(第三版)>第6章:面向对象的程序设计. 上节已经提到 ...

  9. 深入理解javascript原型和闭包(5)——instanceof

    又介绍一个老朋友——instanceof. 对于值类型,你可以通过typeof判断,string/number/boolean都很清楚,但是typeof在判断到引用类型的时候,返回值只有object/ ...

随机推荐

  1. D. Book of Evil

    D. Book of Evil time limit per test 2 seconds memory limit per test 256 megabytes input standard inp ...

  2. 浅谈NSBundle

    图片.xib等资源文件无法直接封入静态库,要想在静态库中使用他们,就必须借助于bundle 那么什么是bundle呢? 简单来说,bundle就是一个内部结构按照标准规则组织的特殊目录,即direct ...

  3. Leetcode 67 Add Binary 大数加法+字符串处理

    题意:两个二进制数相加,大数加法的变形 大数加法流程: 1.倒置两个大数,这一步能使所有大数对齐 2.逐位相加,同时进位 3.倒置两个大数的和作为输出 class Solution { public: ...

  4. C#中Math.Round()实现中国式四舍五入

    C#中Math.Round()实现中国式四舍五入 C#中的Math.Round()并不是使用的"四舍五入"法.其实在VB.VBScript.C#.J#.T-SQL中Round函数都 ...

  5. Android---真机调试时不能识别手机的解决方案

    我自己遇到的问题是VS2013和VS2015中xamarin无法识别到真机,现象就是插上手机开启调试模式,豌豆荚都可以连接上手机,就是VS上没出现手机. 但是低版本的手机貌似又行,4.0.3的. 于是 ...

  6. windows下用golang连接mssql

    版权声明:本文为博主原创文章,未经博主允许不得转载.   目录(?)[+] 安装Microsoft SQL Server Native Client 安装golang的mssql驱动 写测试代码   ...

  7. C# 动态修改dll的签名 以及修改引用该dll文件的签名

    在读取RedisSessionStateProvider配置 提到用mono ceil 来修改程序集以及它的签名,里面GetPublicKey 和GetPubliKeyToken 方法里面那个字符串的 ...

  8. HashMap工作原理(转载)

    转载自:http://www.importnew.com/7099.html  HashMap的工作原理是近年来常见的Java面试题.几乎每个Java程序员都知道HashMap,都知道哪里要用Hash ...

  9. 微信公共账号开发:48001 api unauthorized解决

    微信公众平台开发:获取token成功并且拉取自定义菜单也OK,但是在拉取用户信息和分组信息 是总是出现这个 {"errcode":48001,"errmsg": ...

  10. Python中的字典排序

    我想将 b = {'a':234,'b':1,'c':2,'e':2387} 分别按照key和value进行排序,该怎样办呢? Python中比较常用的排序有两个函数, 一.定义 (1)一个是List ...