爱易网
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 浏览次数:20377 次
{{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 排序 行拖拽 行数据下移 行数据上移
免责声明:
本文仅代表作者个人观点,与爱易网无关。其原创性以及文中陈述文字和内容未经本站证实,对本文以及其中全部或者部分内容、文字的真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
相关资料
更多>
ul li弹出菜单有关问题
正则表达式,高人进。解决办法
js提示无对象,小弟我应该怎么改啊
Bootstrap和jQuery UI是同一类的货色吗
Extjs4 简略的Tree panel树例子
【广州】招聘java软件工程师解决思路
不刷新样式如何起作用
js禁用回退键[backspace键]浏览历史跳转的解决方法
最新的JS奇效资料论坛
推荐阅读
更多>
页面中调用了哪些js函数解决方案
将PHP数组赋值给JS经过php系统函数json_encode()来实现
jsp,servlet中文乱码有关问题
extjs grid的一个范例
JSP运行原理及运作过程
提选select所有值
JNDI获取数据源范例(jsp)
jquery,js,加载等候的效果
Ecside 怎么提交jsp
jsp+mysql文章内容分页展示
【求教】为啥javascript里数字太大后运算 不再准确
javascript兑现螺旋数组
请问一个js递归循环的有关问题。求大神解答
Fastjson黑幕 -转
解决javascript的Math.pow()误差有关问题
js函数 形参默许
Ext类的 Method 与 Event 有什么区别?该如何解决
baidu_maps_api查询地图信息有关问题
js如何理解局部变量,为什么能活上来
急在线解等结贴解决思路