javascript变量提升和闭包理解

我们先来看一个题目:

<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闭包函数访问外部变量的方法
  • 深入Javascript函数、递归与闭包(执行环境、变量对象与作用域链)使用详解
  • javascript中运用闭包和自执行函数解决大量的全局变量问题
  • 理解Javascript_15_作用域分配与变量访问规则,再送个闭包
  • javascript循环变量注册dom事件 之强大的闭包
  • JavaScript中通过闭包解决只能取得包含函数中任何变量最后一个值的问题
  • JavaScript 变量作用域及闭包
(0)

相关推荐

  • javascript中运用闭包和自执行函数解决大量的全局变量问题

    但是从全局看来,这样会导致出现一些让我们难以掌控的情况的出现:变量同名.多个函数共用一个全局变量后的值的变换--等等.所以,有时候,对于一些简单的全局变量,我们可以通过另一种方式来处理--用自执行函数+闭包的方法来解: 比如:我们要在网页加载时给出一个提示,在网页关闭时给出另一个提示 下面的代码,实现了以上功能 复制代码 代码如下: var msg1 = "欢迎光临!"; // 定义一个全局变量 var msg2 = "再见!" //定了另一个全局变量 window

  • javascript循环变量注册dom事件 之强大的闭包

    今天遇到了这个问题: 复制代码 代码如下: //伪代码 for (var i=0; i<n; i++) { addEvent(obj[i], "click", func(i)); } 结果出现了问题,所有的dom都被注册了 i=n 的时候的事件,查了一些资料,说是在循环过程过this被改变,注册过的事件也被随之改变,找到了一种解决方法; 复制代码 代码如下: for (var i=0; i<n; i++) { (function (i){addEvent(obj[i], &

  • 深入Javascript函数、递归与闭包(执行环境、变量对象与作用域链)使用详解

    函数表达式 1.JavaScript中定义函数有2钟方法: 1-1.函数声明: 复制代码 代码如下: function funcName(arg1,arg2,arg3){  //函数体} ①name属性:可读取函数名.非标准,浏览器支持:FF.Chrome.safari.Opera. ②函数声明提升:指执行代码之前会先读取函数声明.即函数调用可置于函数声明之前. 1-2.函数表达式: 复制代码 代码如下: var funcName = function(arg1,arg2,arg3){  //函

  • JavaScript闭包函数访问外部变量的方法

    闭包是指有权访问另一个函数作用域中的变量的函数,但作用域的配置机制有一个需要注意的地方,即闭包只能取得包含函数中任何变量的最后一个值. 如以下案例: function create(){     var arr = new Array();        for (var i=0; i<10; i++){         arr[i] = function(){             return i;         };      }       return arr; }   var c

  • JavaScript 变量作用域及闭包第1/2页

    实例一: 复制代码 代码如下: <script type="text/javascript"> var i = 1; // 弹出内容为 1 true 的提示框 alert(window.i + ' ' + (window.i == i)); </script> 分析: 在全局定义的变量其实就是 window 对象的属性. 上面的例子可以看到,我们定义全局变量的同时,window 对象会产生一个相应的属性,如何让我们的代码避免产生这个属性呢,看下面的例子. 实例二

  • JavaScript中通过闭包解决只能取得包含函数中任何变量最后一个值的问题

    复制代码 代码如下: <script type="text/javascript"> function createArray() { var arr = new Array(); for (var i = 0; i < 10; i++) { arr[i] = function () { return i; } } return arr; } var funcs = createArray(); for (var i = 0; i < funcs.length;

  • 理解Javascript_15_作用域分配与变量访问规则,再送个闭包

    作用域分配与变量访问规则 在 ECMAScript 中,函数也是对象.函数对象在变量实例化过程中会根据函数声明来创建,或者是在计算函数表达式或调用 Function 构造函数时创建.(关于'函数对象'请见<理解Javascript_08_函数对象>).每个函数对象都有一个内部的 [[scope]] 属性,这个属性也由对象列表(链)组成.这个内部的[[scope]] 属性引用的就是创建它们的执行环境的作用域链,同时,当前执行环境的活动对象被添加到该对象列表的顶部.当我们在函数内部访问变量时,其实

  • javascript变量提升和闭包理解

    我们先来看一个题目: <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'被保

  • 最通俗易懂的javascript变量提升详解

    如下所示: a = 'ghostwu'; var a; console.log( a ); 在我没有讲什么是变量提升,以及变量提升的规则之前, 或者你没有学习过变量提升,如果按照现有的javascript理解, 对于上述的例子,你可能会认为第3行代码的输出结果应该是undefined, 因为第二行是var a; 声明变量,但是没有赋值,所以a的值是undefined, 但是正确的结果是ghostwu. 至于为什么,请继续往下看! console.log( a ); var a = 'ghostw

  • 简单谈谈JavaScript变量提升

    目录 前言 1. 什么变量提升? 2. 为什么会有变量提升? (1)提高性能 (2)容错性更好 3. 变量提升导致的问题 (1)变量被覆盖 (2)变量没有被销毁 4. 禁用变量提升 5. JS如何支持块级作用域 (1)创建执行上下文 (2)执行代码 6. 暂时性死区 总结 前言 在 ECMAScript6 中,新增了 let 和 const 关键字用来声明变量.在前端面试中也常被问到 let.const和 var 的区别,这就涉及到了变量提升.暂时性死区等知识点.下面就来看看什么是变量提升和暂时

  • JavaScript变量提升和严格模式实例分析

    本文实例讲述了JavaScript变量提升和严格模式.分享给大家供大家参考,具体如下: 1.什么是变量提升 所谓的变量提升指的是:函数声明和变量声明总是会被解释器悄悄地被"提升"到方法体(作用域)的最顶部. 下面我们通过一个例子来详细说明一下. //变量声明在使用之前 var x; console.log(x);//undefined //变量声明在使用之后 console.log(y);//undefined var y; //上面的式子可以写成下面的样子 /* 变量提升:把x,y提

  • 详解javascript 变量提升(Hoisting)

    简介 "变量提升"意味着变量和函数的声明会在物理层面移动到代码的最前面,但这么说并不准确. 实际上变量和函数声明在代码里的位置是不会动的,而是在编译阶段被放入内存中. 声明变量的方法 var.let.const 不用以上关键字直接赋值的变量会挂载与windows环境下; let a=9 const a=1 var a=6 c=5 声明函数的方法 javascript中声明函数的方法有两种:函数声明式和函数表达式. //函数声明 function say(){ console.log('

  • JavaScript中变量提升和函数提升的详解

    第一篇文章中提到了变量的提升,所以今天就来介绍一下变量提升和函数提升.这个知识点可谓是老生常谈了,不过其中有些细节方面博主很想借此机会,好好总结一下. 今天主要介绍以下几点: 1. 变量提升 2. 函数提升 3. 为什么要进行提升 4. 最佳实践 那么,我们就开始进入主题吧. 1. 变量提升 通常JS引擎会在正式执行之前先进行一次预编译,在这个过程中,首先将变量声明及函数声明提升至当前作用域的顶端,然后进行接下来的处理.(注:当前流行的JS引擎大都对源码进行了编译,由于引擎的不同,编译形式也会有

  • JavaScript中的变量提升和函数提升

    目录 前言 为什么有变量提升 javascript变量提升和函数提升 总结 前言 在js中对变量进行操作后打印值经常会出现undefined的现象.其实原因是因为js中有一个叫做变量提升的功 举例: var data="lyyyyy"; getData(); function getData(){ //第一次打印 console.log("data值为: ", data); var data="yyyyyyy"; //第二次打印 console.

  • 深入理解Javascript作用域与变量提升

    下面的程序是什么结果? 复制代码 代码如下: var foo = 1;function bar() { if (!foo) {  var foo = 10; } alert(foo);}bar(); 结果是10: 那么下面这个呢? 复制代码 代码如下: var a = 1;function b() { a = 10; return; function a() {}}b();alert(a); 结果是1. 吓你一跳吧?发生了什么事情?这可能是陌生的,危险的,迷惑的,同样事实上也是非常有用和印象深刻

  • Javascript变量函数声明提升深刻理解

    目录 前言: 变量提升 函数提升 为什么要提升? 最佳实践 总结 前言: Javascript变量函数声明提升(Hoisting)是在 Javascript 中执行上下文工作方式的一种认识(也可以说是一种预编译),从字面意义上看,“变量提升”意味着变量和函数的声明会在物理层面移动到代码的最前面,在代码里的位置是不会动的,而是在编译阶段被放入内存中会和代码顺序不一样.变量函数声明提升虽然对于实际编码影响不大,特别是现在ES6的普及,但作为前端算是一个基础知识,必须掌握的,是很多大厂的前端面试必问的

随机推荐