语句

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;}
}
})();

最新文章

  1. poj 2513 Colored Sticks trie树+欧拉图+并查集
  2. IOS中的多线程之GCD
  3. iOS应用架构谈:架构设计的方法论
  4. 『重构--改善既有代码的设计』读书笔记----Change Reference to Value
  5. setitimer()函数使用
  6. CAS进行https到http的改造方案,结合cookie源码分析
  7. 头文件limits—各个类型的数据的范围
  8. ubuntu 使用第一天
  9. WCF实现长连接
  10. shell脚本添加实例化参数
  11. Jetson TX2(1)ubutu1604--安装Nvidia Linux驱动
  12. Response重定向实现参数隐藏
  13. echarts 与 百度地图bmap结合系列: 如何设置地图缩放级别和监听缩放事件
  14. java多线程16:join()的使用
  15. elasticsearch之kibana安装
  16. Java EE业务处理流程与XML的引入
  17. L1-036 A乘以B
  18. 吴裕雄 实战PYTHON编程(6)
  19. 笔记一:python安装和执行
  20. python之爬虫_模块

热门文章

  1. centos网卡错误Device eth0 does not seem to be present
  2. (转)雅虎WEB前端网站优化 -- 34条军规
  3. js程序设计02——变量、作用域问题
  4. iOS数据持久化-OC
  5. 修改Android签名证书keystore的密码、别名alias以及别名密码
  6. Jsp技术总结
  7. Maven之问题解决汇总
  8. 今日例子border
  9. 01、手把手Android攻城入门
  10. React学习资料