JavaScript中的作用域和闭包

首先强烈安利《你不知道的JavaScript》,JS初学者进阶必读。

对于从C++、Java等静态语言转向JavaScript的初学者(比如我)来说,JS一些与众不同而又十分要紧的特性使得它显得十分诡异而难以捉摸,为此必须下一番大力气,一边啃书一边实践将这些概念彻底搞懂,然后才谈得上进一步学习前端姿势。(注:本文里的JS以ECMAScript 5(ES5)为准,ES6的新特性我也是刚刚接触,希望今后能与大家一起学习探讨。)

熟悉Java的童鞋在初学JS时,必须要牢记一点:

JS中没有块级作用域!

{
    var test=10;
}
console.log(test);    // 控制台输出:10

纳尼?是不是看着很别扭?还有更坑爹的:

var obj={
    test:10,
    myFunc:function(){
        console.log(test);
    }
};
obj.myfunc();   // 出错,或者IDE直接报警了

同一个对象,自己的函数都不认自己的属性了?

还真是。

对于初学者而言,可以这样认为:除了全局作用域之外,JS只有一种作用域,即函数作用域。(try catch{}语句也可以定义作用域,不过目前为止我还没实际用过)

也就是说,写在函数体内的变量,只要不是嵌套在更深层的函数里,就是处在同一作用域的,“互相可见”;而其他的花括号,不管是for后跟的,if后跟的,还是对象字面量的,一概“不作数”,起不到定义作用域的效果,变量声明写在那些花括号的里面或外面都一样。

那位于嵌套的函数里的作用域呢?它们享有“单向透明”的特权,即:在较内层次的作用域内可以访问较外层次作用域里的变量,反之则不行。

function outerFunc(){
    for(var i=0;i<10;i++){doSomething;}
    console.log(i); // 控制台输出10,因为i位于outerFunc的作用域
    var outer = 10;
    function innerFunc(){
        var inner = outer; // 内层作用域可以访问外层作用域里的变量
    }
    console.log(inner); // 报错,外层作用域访问不到内层作用域里的变量
}

再来分析上一个例子。我们试图在myFunc的作用域内部访问test,然而test并不是一个“与myFunc位于同一个对象作用域”的变量,事实上根本不存在“对象作用域”这回事,test是obj的一个属性,不是一个“独立”的变量,要访问test只能通过点运算符obj.test或obj["test"],哪怕是在myFunc内部。当然,myFunc内部可以访问到obj这个位于外层作用域的变量,没有问题。于是将代码改写如下:

var obj={
    test:10,
    myFunc:function(){
        console.log(obj.test);
    }
};
obj.myfunc();   // 10

既然在内层作用域里可以访问外层作用域,那么就产生了一个有趣的现象,叫做“闭包”。制造一个闭包只需要两步:

1.在内层函数里引用外层函数的变量

2.将内层函数作为外层函数的返回值返回出去

function outer(){
    var test = 10;
    var inner = function(){
        console.log(test++);
    };
    return inner;
}

var myFunc = outer(); // 将outer的返回值(inner函数)赋给myFunc
myFunc(); // 10
myFunc(); // 11
myFunc(); // 12

这个被返回的inner函数就是一个闭包。虽然outer函数运行结束了,但它的内部变量test因为被闭包引用,所以并没有被销毁,而是被保存了起来,并且可以通过闭包继续操作。当然,外界永远无法访问test这个变量,它成了inner(以及myFunc)所指向的函数的“私有变量”。

时间: 2024-10-18 16:10:37

JavaScript中的作用域和闭包的相关文章

Javascript中关于作用域和闭包和域解释的面试题

<script type="text/javascript"> function fn() { var i = 10; return function (n) { console.log(n + (++i)) } } var f = fn();//首先把fn执行,然后把执行的结果赋值给f,函数执行只要看函数里面有没有return f(10);//10+11=21; f(20);//20+12=32; fn()(10);//10+11=21 fn()(20)//20+11=3

JavaScript中的作用域链和闭包

JavaScript中的作用域链和闭包 2012-06-29 11:41 1878人阅读 评论(46) 收藏 举报 JavaScript中出现了一个以前没学过的概念——闭包.何为闭包?从表面理解即封闭的包,与作用域有关.所以,说闭包以前先说说作用域. 作用域(scope) 通常来说一段程序代码中使用的变量和函数并不总是可用的,限定其可用性的范围即作用域,作用域的使用提高了程序逻辑的局部性,增强程序的可靠性,减少名字冲突. 全局作用域(Global Scope) 在代码中任何地方都能访问到的对象拥

JavaScript函数,作用域以及闭包

JavaScript函数,作用域以及闭包 1. 函数 (1). 函数定义:函数使用function关键字定义,它可以用在函数定义表达式或者函数声明定义. a. 函数的两种定义方式: * function functionName() {} * var functionName = function(){} b. 两种函数定义不同之处 1). 声明提前问题 函数声明语句   :声明与函数体一起提前 函数定义表达式 :声明提前,但是函数体不会提前 请看下面图示:绿色线上面实在js初始加载的时候,查看

javascript中的原型和闭包

定义 //闭包测试 function bbTest() { var local = "这里是本地变量"; //闭包会扩大局部变量的作用域,具备变量一致会存活到函数之外,在函数之外可以访问 this.show = function () { return local; } } //非闭包测试 function fbbTest() { var local = "这里是本地变量"; } fbbTest.prototype.show = function () { retu

javascript中函数作用域之”提升“

javascript中函数作用域之变量提升 当我们在函数内部用关键字var声明一个变量的时候,此变量的作用域限制在当前函数. 提升:在一个作用域内部,不管一个变量用var声明的位置在哪里,这个变量属于当前整个作用域,并且在当前作用域的任何位置都可以访问它.在javascript中,这种行为/现象称之为"提升",即一个变量在一个作用域的任何位置用var声明,javascript引擎都会把这些用var声明的变量"移动"到当前作用域的开始处. 谈到javascript这种

前端学习 第六弹: javascript中的函数与闭包

前端学习 第六弹:  javascript中的函数与闭包 当function里嵌套function时,内部的function可以访问外部function里的变量 function foo(x) {    var tmp = 3;    function bar(y) {        alert(x + y + (++tmp));    }    bar(10);}foo(2) 这时无论怎么运行输出的都是16,但这不是闭包 如果我们返回内部函数,内部function会close-over外部fu

【翻译】JavaScript中的作用域和声明提前

原文:http://www.adequatelygood.com/JavaScript-Scoping-and-Hoisting.html ===翻译开始=== 你知道下面的JavaScript脚本执行结果是什么吗? 1 var foo=1; 2 function bar(){ 3 if(!foo){ 4 var foo=10; 5 } 6 alert(foo); 7 } 8 bar(); 如果你对弹出的结果是"10"感到惊讶的话,那么下面这段脚本会让你晕头转向的: 1 var a=1

JS中的作用域和闭包

作用域:在编程语言中,作用域控制着变量与参数的可见性及生命周期.JS确实有函数作用域,那意味着定义在函数中的参数和变量在函数外部是不可见的,而且在一个函数中的任何位置定义的变量在该函数中的任何地方都是可见的. var a = 1; var fs = function (){ var b = 2; var c = 4 var fun = function (){ var c = 3; alert(a) //输出1 alert(b) //输出2 alert(c) //输出3 } fun(); } f

JavaScript中的作用域 、作用域链和闭包

JavaScript中作用,作用域链和闭包详解 一.作用域在js中有全局变量和局部变量之分:比如var a = 1;function sum(){var b=1console.log(b) //1console.log(a) //2 }sum()console.log(a) //3console.log(b) //4 例子中 a 是全局变量,b是局部变量(定义在函数内部,只能在函数内部访问)所以第1行正确 函数内部也能访问全局变量 a所以第2行也能正确 第三行也正确.第4行有外部不能访问内部变量