爱易网
IT新闻
IT新闻
爱易资讯
网站搭建
云虚拟主机教程
云服务器教程
Apache教程
IIS教程
Nginx教程
网站策划
站长文章
推广教程
淘宝客教程
网页设计
HTML教程
XHTML教程
CSS教程
HTML5教程
CSS3教程
JavaSript基础
JQuery教程
Node.js教程
前端技术
Ajax教程
Js特效
Xml教程
平面设计
页面UI设计
photoshop教程
程序开发
AI人工智能
Asp教程
Php教程
Asp.Net教程
Net Core教程
C#教程
Java教程
Jsp教程
开发技术
微信小程序教程
Uniapp开发教程
微信公众号开发
Andriod教程
IOS教程
DOS教程
Python教程
Docker教程
Windows Container教程
数据库
MSSQL教程
MySQL教程
Redis教程
Access教程
Oracle教程
数据库教程
操作系统
Linux教程
Windows教程
MAC教程
Cisco教程
交换机教程
防火墙教程
搜索
爱易网页
JavaSript
{{JS}}函数作用域跟闭包
{{JS}}函数作用域跟闭包
日期:2014-05-16 浏览次数:20389 次
{{JS}}函数作用域和闭包
1.词法作用域
Javascript中的函数是通过词法来划分作用域的,而不是运态地划分作用域的,即“
在Javascript中,函数运行在定义它们的作用域,而不是运行在执行它们的作用域中
”。这句话可理解为:
当使用function定义一个函数时,当前作用域被保存起来,并且成为函数内部状态的一部分。在最顶级,使用域链仅由全局对象组成,而并不和词法作用域相关。然而当定义一个嵌套的函数时,作用域链就包括外围的包含函数。这意味着嵌套的函数可以访问包含函数的所有参数和局部变量。
注:尽管当一个函数定义时,作用域链便固定了,但作用域链中定义的属性还没有固定。作用域链是“活的”,并且函数在被调用时可以访问当前的绑定。
2.调用对象
当JS解释器
调用一个函数时
,它
首先将作用域设置为定义函数的时候起作用的那个作用域链
。
接着它在作用域链的前面添加一个新的对象,称为调用对象(call object),
调用对象用一个名为arguments的属性来初始化,这个属性引用了函数的Arguments对象。函数的命名参数添加到调用对象的后面。而用var语句声明的任何局部变量也都定义在这个对象中。既然这个调用对象位于作用域链的前端,局部变量,函数参数及Arguments对象都在函数内的作用域中。当然,这也意味着它们可以隐藏作用域链更上层的任何同名属性。
注:和arguments不同,this是一个关键字,而不是调用对象的一个属性。
3.作为名字空间的调用对象
有时定义一个只是创建调用对象的函数,这个调用对象充当一个临时的名字空间,可以在该名字空间中定义变量并创建属性,而不会破坏全局的名字空间。如下:
(function() {
// todo :
})();
4.作为闭包的嵌入函数
Javascript允许嵌入的函数,允许函数用作数据,并且使用词法作用域,这些因素相互作用可以产生惊人的效果。比如考虑一个定义在函数f中的函数g。当f被调用时,作用域链包含了对f的这一调用的调用对象,后边是全局对象。g定义在f中,因此这个作用域链保存为g的定义的一部分。当g被调用时,作用域链包含3个对象:它自己的调用对象,
f的调用对象
及全局对象。
1)当嵌入的函数在它们定义的同一词法作用域中调用时,它们是很好理解的。如下
var a = "global";
function f() {
var a = "local";
function g() { console.log(a); }
g();
}
f();// local
2)考虑如下代码,其中包含了一个函数,它返回一个嵌套的函数。如下代码每次调用makefunc函数时它都返回一个函数。返回的函数的代码都一样。但它所创建的作用域略有不同,因为外围函数的参数值在每次调用时都不同,即外围函数的每次调用的作用链上有一个不同的调用对象。
function makefunc(x) {
return function() { return x; }
}
var a = [makefunc(0), makefunc(1), makefunc(2)];
console.log(a[0]()); // 0
console.log(a[1]()); // 1
console.log(a[2]()); // 2
这段代码的结果正是可以从严格应用词法作用域规则所期待的:函数在它所定义的作用域中执行。然而这些结果令人吃惊的原因是:当定义了局部作用域的函数退出时期待局部作用域能够终止并退出。当一个函数被调用时,就为它创建一个调用对象并放置到作用域链中。当函数退出时,调用对象也从作用域链中移除。当没有涉及嵌套的函数时,作用域链是对调用对象的惟一的引用。当对象从链中移除了,也就没有对它的引用了,最终通过对它的垃圾收集而完结。
但是,嵌套函数改变了这一情景。如果创建一个嵌套函数,这个函数的定义引用了调用对象,因为调用对象在这个函数所定义的作用域链的顶端。可是当嵌套函数只在外围函数的内部调用时,那么对嵌套函数的惟一引用在调用对象中。当外围函数返回时,嵌套函数引用了调用对象,并且调用对象引用了嵌套函数,但是没有其它东西引用它们二者,因此对这两个对象都可以进行垃圾收集了。
如果把嵌套函数的引用保存到一个全局作用域(另一个作用域)中,情况又不同了。使用嵌套的函数作为外围函数的返回值,或者把嵌套的函数存储为某个其它对象的属性。此时,有一个对嵌套函数的外部引用,并且嵌套函数将它的引用保留给外围函数的调用对象。结果是,外围函数的一次特定调用的调用对象仍然存在,函数的参数和局部变量的名字和值在这个对象中得以维持。Javascript代码不会以任何方式直接访问调用对象,但它所定义的属性是对嵌入函数任何调用的作用域链的一部分。(注:若一个外围函数存储了两个嵌套函数的全局引用,这两个嵌套函数共享同一个调用对象,并且,一个函数的一次引用所做出的改变对于另一个函数的调用来说是可见的。)
Javascript函数是将要执行的代码以及执行这些代码的作用域构成的一个综合体,这种代码和作用域的综合体称为闭包。所有的Javascript函数都是闭包。而当一个嵌套函数被导出到它所定义的作用域时,这种闭包才是最有趣的。所以当一个嵌套函数以这种方式使用时,我们明确地称之为闭包。
如下闭包的示例:
var uniqueId = (function() {
var id = 0;
return function() { return id++; };
})();
//模拟私有属性
function makeProperty(o, name, predicate) {
var value;
o["get" + name] = function() { return value; };
o["set" + name] = function(v) {
if(predicate && !predicate(v)) {
throw new Error("set" + name + ": invalid value " + v);
} else {
value = v;
}
}
}
上一篇: ssh如何知道删除实体成不成功
下一篇: Extjs3.x 为GridPanel 排序 行拖拽 行数据下移 行数据上移
免责声明:
本文仅代表作者个人观点,与爱易网无关。其原创性以及文中陈述文字和内容未经本站证实,对本文以及其中全部或者部分内容、文字的真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
相关资料
更多>
ExtJS4组件_Grid配备-属性-方法详解-案例
JavaScript适用小技巧
JavaScript在页面中的位置,加载与运作
jsp与mysql配合使用时 中文乱码 解决办法
怎么获取到alert的的显示值
js循环用文本框显示值有关问题
一段小程序的不解解决办法
范例讲解JS复选框动态计算表格每列总和
怎么同过自定义属性获取div对象
推荐阅读
更多>
easyui datagrid 怎么动态改变某列的数据
怎么在javascript里解析json数据
javascript汉语言经典帮助手册.rar
以上代码为什么不能成功?用到jquery
jsp取得用户真实IP地址
查找BR前的内容,该怎么解决
请问一下,有关这两段得到同样结果的程序执行速度有关问题.Javascript
怎么禁止鼠标滚轮事件
jquery选择父节点解决思路
上载jseclipse
怎么屏蔽图片操作
js 获取json 格式的数据 怎的根据变量获取数据
struts2中以json的模式输出一张页面到前台
关于tr的onclick事件和tr里的<img>的onClick事件同时触发的有关问题
js 动态表使用checkbox全选(单选)的删除有关问题!(附代码)
dwr util.js工具包的施用
用JS固定报表列
求大神指点:Jquery ui position有关问题
json格式字符串跟json对象的转换
javascript兼容性集锦(IE/FF)