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 相关文章推荐
JS实现打开本地文件或文件夹
Mar 09 Javascript
jquery中filter方法用法实例分析
Feb 06 Javascript
jQuery使用load()方法载入另外一个网页文件内的指定标签内容到div标签的方法
Mar 25 Javascript
基于jQuery倾斜打开侧边栏菜单特效代码
Sep 15 Javascript
基于jQuery实现数字滚动效果
Jan 16 Javascript
浅谈Vue父子组件和非父子组件传值问题
Aug 22 Javascript
基于vue-cli 打包时抽离项目相关配置文件详解
Mar 07 Javascript
NProgress显示顶部进度条效果及使用详解
Sep 21 Javascript
Vue程序化的事件监听器(实例方案详解)
Jan 07 Javascript
基于JQuery实现页面定时弹出广告
May 08 jQuery
精读《Vue3.0 Function API》
May 20 Javascript
微信小程序实现多行文字滚动
Nov 18 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 Socket写的POP3类
2013/10/30 PHP
thinkphp3.2点击刷新生成验证码
2016/02/16 PHP
php安装扩展mysqli的实现步骤及报错解决办法
2017/09/23 PHP
Django中通过定时任务触发页面静态化的处理方式
2018/08/29 PHP
thinkphp5框架路由原理与用法详解
2020/02/11 PHP
PHP使用openssl扩展实现加解密方法示例
2020/02/20 PHP
js中实现多态采用和继承类似的方法
2014/08/22 Javascript
js实现支持手机滑动切换的轮播图片效果实例
2015/04/29 Javascript
JS验证逗号隔开可以是中文字母数字
2016/04/22 Javascript
详解js界面跳转与值传递
2016/11/22 Javascript
AJAX和jQuery动态加载数据的实现方法
2016/12/05 Javascript
Node.JS更改Windows注册表Regedit的方法小结
2017/08/18 Javascript
VUE饿了么树形控件添加增删改功能的示例代码
2017/10/17 Javascript
响应式框架Bootstrap栅格系统的实例
2017/12/19 Javascript
Vue render函数实战之实现tabs选项卡组件
2019/04/22 Javascript
layUI的验证码功能及校验实例
2019/10/25 Javascript
vue实现网络图片瀑布流 + 下拉刷新 + 上拉加载更多(步骤详解)
2020/01/14 Javascript
element-ui和vue表单(对话框)验证提示语(残留)清除操作
2020/09/11 Javascript
python Django连接MySQL数据库做增删改查
2013/11/07 Python
详解Python当中的字符串和编码
2015/04/25 Python
Python对多属性的重复数据去重实例
2018/04/18 Python
python3.4.3下逐行读入txt文本并去重的方法
2018/04/29 Python
python实现Flappy Bird源码
2018/12/24 Python
python-numpy-指数分布实例详解
2019/12/07 Python
python实现门限回归方式
2020/02/29 Python
PyQt5 如何让界面和逻辑分离的方法
2020/03/24 Python
css3新增颜色表示方式分享
2014/04/15 HTML / CSS
CHARLES & KEITH台湾官网:新加坡时尚品牌
2019/07/30 全球购物
Speedo速比涛德国官方网站:世界领先的泳装品牌
2019/08/26 全球购物
武汉英思工程科技有限公司&ndash;ORACLE面试测试题目
2012/04/30 面试题
网络方面基础面试题
2012/11/16 面试题
Boolean b = new Boolean(“abcde”); 会编译错误码
2013/11/27 面试题
大学生暑期实践感言
2014/02/26 职场文书
村主任“四风”问题个人对照检查材料思想汇报
2014/10/02 职场文书
2015自愿离婚协议书范本
2015/01/28 职场文书
浅谈由position属性引申的css进阶讨论
2021/05/25 HTML / CSS