javascript变量提升和闭包理解


Posted in Javascript onMarch 12, 2018

我们先来看一个题目:

<script>
 console.log(typeof a)//undefined
 var a='littlebear';
 console.log(a)//littlebear 
</script>
<script>
 console.log(typeof a)//string
 var a=1;
 console.log(a)//1
</script>

第一个script里可以看出var a 被提升到顶部,a = 'littlebear'被保留在原地。

第二个script,之所以不先打印undefined ,是因为a在上面已经被var声明过,所以var a不会再次被提升。

再看一个题目:

<script>
  console.log(a)//function a(){}
  var a=1;
  console.log(a)//1
  function a(){}
  console.log(a)//1
</script>

可以看到function a(){}被提升到最顶端。说明函数的提升变量的提升

1.变量提升

在ES6之前,JavaScript没有块级作用域(一对花括号{}即为一个块级作用域),只有全局作
用域和函数作用域。变量提升即将变量声明提升到它所在作用域的最开始的部分。
上个简历的例子如:

console.log(global); // undefined
var global = 'global';
console.log(global); // global

function fn () {
console.log(a); // undefined

var a = 'aaa';

console.log(a); // aaa
}
fn();

之所以会是以上的打印结果,是由于js的变量提升,实际上上面的代码是按照以下来执行的:

var global; // 变量提升,全局作用域范围内,此时只是声明,并没有赋值
console.log(global); // undefined
global = 'global'; // 此时才赋值
console.log(global); // 打印出global
 
function fn () {
var a; // 变量提升,函数作用域范围内

console.log(a);

a = 'aaa';

console.log(a);
}
fn();

2.函数提升

js中创建函数有两种方式:函数声明式和函数字面量式。只有函数声明才存在函数提升!如:

console.log(f1); // function f1() {}  
console.log(f2); // undefined 
function f1() {}
var f2 = function() {}

之所以会有以上的打印结果,是由于js中的函数提升导致代码实际上是按照以下来执行的:

function f1() {} // 函数提升,整个代码块提升到文件的最开始
console.log(f1);  
console.log(f2);  
var f2 = function() {}

3.什么是闭包

闭包是有权访问另一个函数作用域的变量的函数。

简单的说,Javascript允许使用内部函数---即函数定义和函数表达式位于另一个函数的函数体内。而且,这些内部函数可以访问它们所在的外部函数中声明的所有局部变量、参数和声明的其他内部函数。当其中一个这样的内部函数在包含它们的外部函数之外被调用时,就会形成闭包。

4.变量的作用域

要理解闭包,首先要理解变量的作用域。

变量的作用域无非就是两种:全局变量和局部变量。

Javascript语言的特殊之处,就在于函数内部可以直接读取全局变量。

其中内部函数中可以访问外部函数的变量,是因为内部函数的作用域链中包含了外部函数的作用域;

也可以理解为:内部函数的作用范围辐射到了外部函数的作用范围;

var n=999;
function f1(){
 alert(n);
}
f1(); // 999

另一方面,在函数外部自然无法读取函数内的局部变量。

function f1(){
 var n=999;
}
alert(n); // error

这里有一个地方需要注意,函数内部声明变量的时候,一定要使用var命令。如果不用的话,你实际上声明了一个全局变量!

function f1(){
  n=999;
}
f1();
alert(n); // 999

5.闭包的写法和用法

var Circle={ 
  "PI":3.14159, 
  "area":function(r){ 
    return this.PI * r * r; 
  } 
}; 
alert( Circle.area(1.0) );//3.14159

刚开始我没意识到,这样写对象也是一种闭包,今天回头想想,这就是闭包的经典用发啊!

6.使用闭包的注意点

1)由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,在IE中可能导致内存泄露。解决方法是,在退出函数之前,将不使用的局部变量全部删除。

2)闭包会在父函数外部,改变父函数内部变量的值。所以,如果你把父函数当作对象(object)使用,把闭包当作它的公用方法(Public Method),把内部变量当作它的私有属性(private value),这时一定要小心,不要随便改变父函数内部变量的值。

Javascript 相关文章推荐
JQuery UI的拖拽功能实现方法小结
Mar 14 Javascript
如何让div span等元素能响应键盘事件操作指南
Nov 13 Javascript
jquery跟js初始化加载的多种方法及区别介绍
Apr 02 Javascript
Windows 系统下安装和部署Egret的开发环境
Jul 31 Javascript
12306验证码破解思路分享
Mar 25 Javascript
基于javascript实现图片懒加载
Jan 05 Javascript
angularjs使用directive实现分页组件的示例
Feb 07 Javascript
AngularJS中重新加载当前路由页面的方法
Mar 09 Javascript
详解vue添加删除元素的方法
Jun 30 Javascript
详解Vue SSR( Vue2 + Koa2 + Webpack4)配置指南
Nov 13 Javascript
微信小程序bindinput与bindsubmit的区别实例分析
Apr 17 Javascript
Vue在 Nuxt.js 中重定向 404 页面的方法
Apr 23 Javascript
浅谈angular4.0中路由传递参数、获取参数最nice的写法
Mar 12 #Javascript
Vue 仿QQ左滑删除组件功能
Mar 12 #Javascript
JS中touchstart事件与click事件冲突的解决方法
Mar 12 #Javascript
Node.JS循环删除非空文件夹及子目录下的所有文件
Mar 12 #Javascript
Javascript中prototype与__proto__的关系详解
Mar 11 #Javascript
js中document.write和document.writeln的区别
Mar 11 #Javascript
Javascript 编码约定(编码规范)
Mar 11 #Javascript
You might like
让PHP支持页面回退的两种方法[转]
2007/02/14 PHP
一家之言的经验之谈php+mysql扎实个人基本功
2008/03/27 PHP
总结PHP如何获取当前主机、域名、网址、路径、端口和参数等
2016/09/09 PHP
PHP错误处理函数register_shutdown_function使用示例
2017/07/03 PHP
Nigma vs Liquid BO3 第一场2.13
2021/03/10 DOTA
jqPlot 基于jquery的画图插件
2011/04/26 Javascript
各浏览器对click方法的支持差异小结
2011/07/31 Javascript
动态加载js、css等文件跨iframe实现
2014/02/24 Javascript
纯js实现遮罩层效果原理分析
2014/05/27 Javascript
jQuery的观察者模式详解
2014/12/22 Javascript
JQuery中DOM事件合成用法实例分析
2015/06/13 Javascript
js实现滚动条滚动到页面底部继续加载
2015/12/19 Javascript
JS 验证密码 不能为空,必须含有数字、字母、特殊字符,长度在8-12位
2017/06/21 Javascript
详解Node.js 中使用 ECDSA 签名遇到的坑
2018/11/26 Javascript
react组件从搭建脚手架到在npm发布的步骤实现
2019/01/09 Javascript
通过js给网页加上水印背景实例
2019/06/17 Javascript
使用jquery-easyui的布局layout写后台管理页面的代码详解
2019/06/19 jQuery
vue实现单一筛选、删除筛选条件
2020/10/26 Javascript
Vue 修改网站图标的方法
2020/12/31 Vue.js
[04:14]从西雅图到上海——玩家自制DOTA2主题歌曲应援TI9
2019/07/11 DOTA
python使用urllib模块和pyquery实现阿里巴巴排名查询
2014/01/16 Python
Python利用Beautiful Soup模块创建对象详解
2017/03/27 Python
python下解压缩zip文件并删除文件的实例
2018/04/24 Python
如何用Python做一个微信机器人自动拉群
2019/07/03 Python
Python csv模块使用方法代码实例
2019/08/29 Python
Python3基本输入与输出操作实例分析
2020/02/14 Python
python turtle工具绘制四叶草的实例分享
2020/02/14 Python
python 爬虫如何正确的使用cookie
2020/10/27 Python
Sephora丝芙兰澳洲官方网站:国际知名化妆品购物
2016/10/27 全球购物
Etam俄罗斯:法国女士内衣和家居服网上商店
2019/10/30 全球购物
CAD制图人员的自荐信
2014/02/07 职场文书
担保书范本
2015/01/20 职场文书
浅谈redis缓存在项目中的使用
2021/05/20 Redis
36个正则表达式(开发效率提高80%)
2021/11/17 Javascript
Windows server 2012搭建FTP服务器
2022/04/29 Servers
Win10此设备不支持接收Miracast无法投影的解决方法
2022/07/07 数码科技