javascript作用域与闭包
Javasript作用域概要
在javascript中,作用域是执行代码的上下文,作用域有三种类型:
1) 全局作用域
2) 局部作用域(函数作用域)
3) eval作用域
var foo = 0; //全局作用域
console.log(foo);//输出0 var myFunction = function() {
var foo = 1; //局部作用域
console.log(foo); //输出1
var myNestedFunction = function() {
var foo = 2;
console.log(foo); //输出2
}();
} ();
eval("var foo=3;console.log(foo);");//eval()作用域
javascript中,函数内部的可以直接读取全局的变量:
取内部的局部变量,例如:
还有需要注意的,在函数内部声明变量的时候,一定要用var命令,如果不用的话,实际声明的是一个全局变量哈
javascript没有块作用域
由于逻辑语句无法创建作用域,因此变量可以互相覆盖,例如:代码执行时,foo是变化的,因为javascript没有块作用域,只有函数,全局和eval作用域
javascript块级作用域中的变量是由其执行环境确定的,例如:
var a=111;
if(true){
var a=222;
}
console.log(a);
输出的是: 222,是因为执行环境是window
例如:
var a=111;
function num(){
var a=333;
if(true){
var a=666;
}
console.log(a);
} num();
console.log(a);
调用 666,111 是因为if块级作用域的执行环境是num函数 ,所以输出666,之后console.log(a),访问的是全局a,所以输出111
作用域链(词法作用域)
当javascript查找与变量关联的值时,会遵循一个查找链。这个链是基于作用域的层次结构的。
例如:查找 sayHiText变量的顺序为;Func2中--àfunc1中 ---》全局变量中
函数的作用域会一层层的查找,当变量没有用var声明变量时,它会一层层的往上找,找到就替换,如果回溯到顶层window时,发现还是没有,
就会把这个变量定义在window下(即全局变量),例如以下代码:
var name="first";
function test(){
var name="second";
function num(){
name="third";
console.log(name);
}
num();
console.log(name);
}
test();
console.log(name);
此时会输出:third third first
这是因为name=”third”并不是局部变量,然后它恰好在test这个大函数中,这时候解析器就在test函数中寻找name,发现有name,就把ctrip的name修改为third。
为了进一步说明,再看如下代码:
var name="first";
function test(){
var name="second";
function num(){
age=28;
name="third";
console.log(name);
}
num();
console.log(name);
}
test();
console.log(name);
console.log(age)
输出为:third third first 28
在test环境中找到了name,但是没有找到age,所以age会一直回溯到window,所以这时候age是全局变量。
如何从外部读取局部变量?
有时候我们需要得到函数内的局部变量,但是,在正常情况下是办不到的,只有通过变通方法实现,那就是在函数的内部,再定义一个函数。
既然f2可以读取f1中的局部变量,那么只要把f2作为返回值,我们就可以在 f1外部读取内部变量了,即f2函数就是闭包。
闭包的概念
闭包就是能够读取其他函数内部变量的函数。由于在javascript中,只有函数内部的子函数才能够读取局部变量,
因此可以把闭包简单理解成“定义在一个函数内部的函数”。所以,在本质上,闭包就是将函数内部和函数外部连接起来的一座桥梁。
既然闭包是函数嵌套函数,例如:
function A(){
var b=1;
function B(){
alert(b++)
}
} A();
这个是闭包吗?
不管执行多少次,都会返回undefined,因为A函数没有return语句,所以默认会返回undefined;
显然上面这个不是闭包,只有当你return内部function时,就是一个闭包;
例如:
function A(x){
var temp=3;
return function(y){
return x+y+(++temp);
}
} var bar=A(2);//bar现在是一个闭包
bar(10);//返回16
bar(10);//返回17,因为每运行一次,temp加1,temp内存并没有释放
闭包的用途
闭包最大的两个用途是: 1) 可以读取函数内部的变量
2)让这些变量的值始终保持在内存中
例如以下代码:
在这段代码中,result实际上就是闭包f2函数, 它一共运行两次,第一次是99,第二次是100。
这就证明了函数f1中的局部变量n一直保存在内存中,并没有在f1调用后被自动清除。
因为f1是f2的父函数,而f2被赋给了一个全局变量,这就导致f2始终在内存中,而f2的存在依赖于f1,因此f1也始终在内存中,不会再调用结束后,被垃圾回收机制回收。
使用闭包的注意点
1) 由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包。
2) 闭包会在父函数外部,改变父函数内部变量的值。
如上,为什么输出的结果是the window 了?
主要有两个知识点:
1) 内部函数可以访问定义它们的外部函数的参数和变量(除了this和arguments之外)
2) 如果需要访问对象的name属性,就需要显示的定义一个变量that来引用this,而这个变量此时就指向了object对象了
getNameFunc的第一个()是属于方法的调用,所以this绑定到了object对象上,自然this.name为the object,但是闭包函数无法访问这个this,它只能访问到全局的this,因此输出的是”the window”
例如:
闭包中的this指向的是全局对象,而getNameFunc中的this指向的是调用者,所以输出的结果如上。例如:
为对象显示定义了that来引用this,因此输出的是 “the object”
闭包经常用于创建含有隐藏数据的函数(但并不总是这样)
例如:
var db = (function() {
// 创建一个隐藏的object, 这个object持有一些数据
// 从外部是不能访问这个object的
var data = {};
// 创建一个函数, 这个函数提供一些访问data的数据的方法
return function(key, val) {
if (val === undefined) { return data[key] } // get
else { return data[key] = val } // set
}
// 我们可以调用这个匿名方法
// 返回这个内部函数,它是一个闭包
})(); db('x'); // 返回 undefined
db('x', 1); // 设置data['x']为1
db('x'); // 返回 1
// 我们不可能访问data这个object本身
// 但是我们可以设置它的成员
javascript作用域与闭包的更多相关文章
- javascript作用域和闭包之我见
javascript作用域和闭包之我见 看了<你不知道的JavaScript(上卷)>的第一部分--作用域和闭包,感受颇深,遂写一篇读书笔记加深印象.路过的大牛欢迎指点,对这方面不懂的同学 ...
- JavaScript 作用域和闭包——另一个角度:扩展你对作用域和闭包的认识【翻译+整理】
原文地址 --这篇文章有点意思,可以扩展你对作用域和闭包的认识. 本文内容 背景 作用域 闭包 臭名昭著的循环问题 自调用函数(匿名函数) 其他 我认为,尝试向别人解释 JavaScript 作用域和 ...
- JavaScript作用域和闭包
在JavaScript中,作用域是执行代码的上下文.作用域有3种类型: 1.全局作用域 2.局部作用域---(又叫函数作用域) 3.eval作用域 var foo =0;//全局作用域console. ...
- 举例详细说明javascript作用域、闭包原理以及性能问题(转)
转自:http://www.cnblogs.com/mrsunny/archive/2011/11/03/2233978.html 这可能是每一个jser都曾经为之头疼的却又非常经典的问题,关系到内存 ...
- JavaScript 作用域和闭包
作用域的嵌套将形成作用域链,函数的嵌套将形成闭包.闭包与作用域链是 JavaScript 区别于其它语言的重要特性之一. 作用域 JavaScript 中有两种作用域:函数作用域和全局作用域. 在一个 ...
- javascript作用域、闭包、对象与原型链
原文作者总结得特别好,自己收藏一下.^-^ 1.作用域1.1函数作用域JS的在函数中定义的局部变量只对这个函数内部可见,称之谓函数作用域.它没有块级作用域(因此if.for等语句中的花括号不是独立作用 ...
- JavaScript作用域与闭包总结
1.全局作用域 所有浏览器都支持 window 对象,它表示浏览器窗口,JavaScript 全局对象.函数以及变量均自动成为 window 对象的成员.所以,全局变量是 window 对象的属性,全 ...
- javascript——作用域与闭包
http://www.cnblogs.com/lucio-yr/p/4047972.html 一.作用域: 在函数内部:用 var 声明的表示局部变量,未用var的是全局变量. 作用域取决于变量定义时 ...
- 《JavaScript 闯关记》之作用域和闭包
作用域和闭包是 JavaScript 最重要的概念之一,想要进一步学习 JavaScript,就必须理解 JavaScript 作用域和闭包的工作原理. 作用域 任何程序设计语言都有作用域的概念,简单 ...
随机推荐
- xcode下载低版本模拟器速度缓慢解决方案
随着苹果系统的更新和迭代,现在app开发中需要适配的除了需要适配屏幕尺寸以外,还需要适配系统版本.系统版本测试如果有条件可以使用各种系统版本的真机进行适配,如果没有这个条件,也可以采用xcode的模拟 ...
- IDEA中配置svn
反正这个命令行我是勾选了的,软件占用内存不大,我就都选了. 然后是配置IDEA 试一下效果,果然阔以,哈哈.
- Android小应用之拨号器
首先看一下Android Studio下怎么设置应用的ICON Activity的onCreate()方法 当界面刚被创建时会回调此方法,super.onCreate()执行父类的初始化操作,必须要加 ...
- Python snap
orderedDict enum sys.path 注册装饰器 装饰器检查 入参 Flask01 flask_script flask blue print functools.partial dns ...
- Warning: (3719, “‘utf8’ is currently an alias for the character set UTF8MB3, which will be replaced by UTF8MB4 in a future release. Please consider using UTF8MB4 in order to be unambiguous.”)
[1]本地版本 Mysql 8.0.12 创建表SQL: DROP TABLE IF EXISTS students; CREATE TABLE `students` ( `sId` ) UNSIGN ...
- VS使用WEB DEPLOY发布
背景是这样的,公司有两台服务器,平时一台备用,另一台做为主生产机器.当有大量补丁或者安装什么东西需要重启的时候,交其中一台直接关掉IIS,然后重启即可,此时另一台负责处理用户请求. 之前一台服务器一个 ...
- python利用正则表达式提取字符串
前言 正则表达式的基础知识就不说了,有兴趣的可以点击这里,提取一般分两种情况,一种是提取在文本中提取单个位置的字符串,另一种是提取连续多个位置的字符串.日志分析会遇到这种情况,下面我会分别讲一下对应的 ...
- 【BZOJ3926】[Zjoi2015]诸神眷顾的幻想乡 广义后缀自动机
[BZOJ3926][Zjoi2015]诸神眷顾的幻想乡 Description 幽香是全幻想乡里最受人欢迎的萌妹子,这天,是幽香的2600岁生日,无数幽香的粉丝到了幽香家门前的太阳花田上来为幽香庆祝 ...
- Python菜鸟之路:Python基础-模块
什么是模块? 在计算机程序的开发过程中,随着程序代码越写越多,在一个文件里代码就会越来越长,越来越不容易维护.为了编写可维护的代码,我们把很多函数分组,分别放到不同的文件里,分组的规则就是把实现了某个 ...
- 3.写一个hello world页面
经过1和2的学习,现在已经可以正常启动Django了,这一节说怎么写一个hello world页面,所有的环境基础就是1和2中搭建的 1.在app模块中添加页面 具体为 hello_django\he ...