搜索
首页web前端js教程javascript作用域和闭包使用详解_基础知识

作用域的嵌套将形成作用域链,函数的嵌套将形成闭包。闭包与作用域链是 JavaScript 区别于其它语言的重要特性之一。

作用域
JavaScript 中有两种作用域:函数作用域和全局作用域。

在一个函数中声明的变量以及该函数的参数享有同一个作用域,即函数作用域。一个简单的函数作用域的例子:

复制代码 代码如下:

function foo() {
    var bar = 1;
    {
        var bar = 2;
    }
    return bar; // 2
}

不同于C等其它有块作用域的语言,这里将始终返回 2 。

全局作用域,对于浏览器来说可以理解为 window 对象(Node.js则是 global):

复制代码 代码如下:

var bar = 1;
function foo() {}
alert(window.bar); // 1
alert(window.foo); // "function foo() {}"

对于变量 bar 和函数 foo 都属于全局作用域,都是 window 的一个属性。

作用域链
在 JavaScript 中访问一个变量时,将从本地变量和参数开始,逐级向上遍历作用域直到全局作用域。

复制代码 代码如下:

var scope = 0, zero = "global-scope";
(function(){
    var scope = 1, one = "scope-1";
    (function(){
        var scope = 2, two = "scope-2";
        (function(){
            var scope = 3, three = "scope-3";
            // scope-3 scope-2 scope-1 global-scope
            console.log([three, two, one, zero].join(" "));
            console.log(scope); // 3
        })();
        console.log(typeof three); // undefined
        console.log(scope); // 2
    })();
    console.log(typeof two); // undefined
    console.log(scope); // 1
})();
console.log(typeof one); // undefined
console.log(scope); // 0

在最里层的函数中,各个变量都能被逐级遍历并输出。而倒数第二层的函数中,变量 three 无法遍历找到,所以输出了 undefined 。

举一个通俗点的例子,你准备要花钱买点东西时,会先摸摸自己的钱包,没了你可以找你爸要,你爸也没有就再找你爷爷,... 。而你爸没钱买东西时,他并不会来找你要。

闭包
在一个函数中,定义另一个函数,称为函数嵌套。函数的嵌套将形成一个闭包。

闭包与作用域链相辅相成,函数的嵌套在产生了链式关系的多个作用域的同时,也形成了一个闭包。

复制代码 代码如下:

function bind(func, target) {
    return function() {
        func.apply(target, arguments);
    };
}

那么怎么理解闭包呢?

外部函数不能访问内嵌函数
外部函数也不能访问内嵌函数的参数和变量
而内嵌函数可以访问外部函数的参数和变量
换一个说法:内嵌函数包含了外部函数的作用域
我们再看看之前讲述的作用域链的例子,这次从闭包的角度来理解下:

复制代码 代码如下:

var scope = 0, zero = "global-scope";
(function(){
    var scope = 1, one = "scope-1";
    (function(){
        var scope = 2, two = "scope-2";
        (function(){
            var scope = 3, three = "scope-3";
            // scope-3 scope-2 scope-1 global-scope
            console.log([three, two, one, zero].join(" "));
            console.log(scope); // 3
        })();
        console.log(typeof three); // undefined
        console.log(scope); // 2
    })();
    console.log(typeof two); // undefined
    console.log(scope); // 1
})();
console.log(typeof one); // undefined
console.log(scope); // 0

最里层的函数能访问到其内部和外部定义的所有变量。而倒数第二层的函数无法访问到最里层的变量,同时,最里层的 scope = 3 这个赋值操作并没有对其外部的同名变量产生影响。

再换个角度来理解闭包:

每次外部函数的调用,内嵌函数都会被创建一次
在它被创建时,外部函数的作用域(包括任何本地变量、参数等上下文), 会成为每个内嵌函数对象的内部状态的一部分,即使在外部函数执行完并退出后
看下面的例子:

复制代码 代码如下:

var i, list = [];
for (i = 0; i     list.push(function(){
        console.log(i);
    });
}
list.forEach(function(func){
  func();
});

我们将得到两次 "2" ,而不是预期的 "1" 和 "2" ,这是因为在 list 中的两个函数访问的变量 i 都是其上一层作用域的同一个变量。

我们改动下代码,以利用闭包来解决这个问题:

复制代码 代码如下:

var i, list = [];
for (i = 0; i     list.push((function(j){
        return function(){
            console.log(j);
        };
    })(i));
}
list.forEach(function(func){
  func();
});

外层的“立即执行函数”接收了一个参数变量 i ,在其函数内以参数 j 的形式存在,它与被返回的内层函数中的名称 j 指向同一个引用。外层函数执行并退出后,参数 j (此时它的值为 i 的当前值)成为了其内层函数的状态的一部分被保存了下来。

声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
switch case 内变量的范围switch case 内变量的范围Feb 09, 2024 am 09:00 AM

packagemainimport"fmt"funcmain(){x:=10switchx{case0:y:='a'fmt.Printf("%c\n",y)case1://y='b'//thiscan'tcompile,y:='b'fmt.Printf("%c\n",y)default:y:=

Linux多线程编程锁详解:如何避免竞争和死锁Linux多线程编程锁详解:如何避免竞争和死锁Feb 11, 2024 pm 04:30 PM

在Linux多线程编程中,锁是一种非常重要的机制,可以避免线程间的竞争和死锁。然而,如果不正确使用锁,可能会导致性能下降和不稳定的行为。本文将介绍Linux中的常见锁类型,如何正确使用它们,以及如何避免竞争和死锁等问题。在编程中,引入了对象互斥锁的概念,来保证共享数据操作的完整性。每个对象都对应于一个可称为”互斥锁”的标记,这个标记用来保证在任一时刻,只能有一个线程访问该对象。Linux实现的互斥锁机制包括POSIX互斥锁和内核互斥锁,本文主要讲POSIX互斥锁,即线程间互斥锁。信号量用在多线程

详解Golang函数中的变量作用域详解Golang函数中的变量作用域Jan 18, 2024 am 08:51 AM

Golang函数中的变量作用域详解在Golang中,变量的作用域指的是变量的可访问范围。了解变量的作用域对于代码的可读性和维护性非常重要。在本文中,我们将深入探讨Golang函数中的变量作用域,并提供具体的代码示例。在Golang中,变量的作用域可以分为全局作用域和局部作用域。全局作用域指的是在所有函数外部声明的变量,即在函数之外定义的变量。这些变量可以在整

掌握JavaScript函数的嵌套和作用域掌握JavaScript函数的嵌套和作用域Nov 03, 2023 pm 07:55 PM

掌握JavaScript函数的嵌套和作用域,需要具体代码示例在JavaScript编程中,函数是非常重要的概念。函数的嵌套和作用域能够极大地提高代码的可读性和灵活性。本文将介绍如何正确地使用嵌套函数和作用域,并提供具体的代码示例。函数的嵌套可以理解为在一个函数中定义了另一个函数。这种嵌套的方式能够将代码分成多个小块,使得程序的逻辑更加清晰。同时,嵌套函数还可

Python Lambda表达式:让编程变得更轻松Python Lambda表达式:让编程变得更轻松Feb 19, 2024 pm 09:54 PM

pythonLambda表达式是一个小的匿名函数,它可以将一个表达式存储在变量中并返回它的值。Lambda表达式通常用于执行简单的任务,这些任务可以通过编写一个单独的函数来完成,但Lambda表达式可以使代码更简洁和易读。Lambda表达式的语法如下:lambdaarguments:expressionarguments是Lambda表达式接收的参数列表,expression是Lambda表达式的体,它包含需要执行的代码。例如,以下Lambda表达式将两个数字相加并返回它们的和:lambdax,

JavaScript const关键字的用法及作用JavaScript const关键字的用法及作用Feb 19, 2024 pm 06:30 PM

JavaScript中const的作用和用法JavaScript是一种广泛应用于网页开发的编程语言,其具有灵活性和动态性是其特点之一。在JavaScript中,我们可以使用const关键字来声明一个常量。本文将介绍const关键字的作用和用法,并提供一些具体的代码示例来帮助读者更好地理解。const的作用const(常量)是一种用于声明不可更改的变量的关键字

c语言static的作用和用法是什么c语言static的作用和用法是什么Jan 31, 2024 pm 01:59 PM

c语言static的作用和用法:1、变量作用域;2、生命周期;3、函数内部;4、修饰全局变量;5、修饰函数;6、其他用途;详细介绍:1、变量作用域,当一个变量前有static关键字,那么这个变量的作用域被限制在声明它的文件内,也就是说,这个变量是“文件级作用域”,这对于防止变量的“重复定义”问题很有用;2、生命周期,静态变量在程序开始执行时初始化一次,并在程序结束时销毁等等。

如何解决Python的变量未定义错误?如何解决Python的变量未定义错误?Jun 24, 2023 pm 10:12 PM

Python是一种高级编程语言,它的易用性和流行程度使得它成为了众多程序员的首选语言。与其他语言一样,Python也存在一些常见的错误类型,例如变量未定义错误。当我们在Python中使用一个未定义的变量时,程序就会抛出一个名为“NameError”的异常。这种错误通常出现在以下几种情况下:拼写错误:可能是因为变量名拼写错误导致了变量未定义错误,我们需要仔细检

See all articles

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

AI Hentai Generator

AI Hentai Generator

免费生成ai无尽的。

热门文章

R.E.P.O.能量晶体解释及其做什么(黄色晶体)
3 周前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳图形设置
3 周前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您听不到任何人,如何修复音频
3 周前By尊渡假赌尊渡假赌尊渡假赌

热工具

Dreamweaver CS6

Dreamweaver CS6

视觉化网页开发工具

记事本++7.3.1

记事本++7.3.1

好用且免费的代码编辑器

安全考试浏览器

安全考试浏览器

Safe Exam Browser是一个安全的浏览器环境,用于安全地进行在线考试。该软件将任何计算机变成一个安全的工作站。它控制对任何实用工具的访问,并防止学生使用未经授权的资源。

SublimeText3 英文版

SublimeText3 英文版

推荐:为Win版本,支持代码提示!

ZendStudio 13.5.1 Mac

ZendStudio 13.5.1 Mac

功能强大的PHP集成开发环境