var add_the_handlers = function(nodes){ var i; for (i = 0; i < nodes.length; i += 1){ nodes[i].onclick = function(e){ alert(i); } } };//糟糕的代码
我们先看这个糟糕的列子!这是javascript精粹上面的一个例子,一开始很是迷惑找了半天也找不到答案,最后自己啃书算是明白了一点(只自己明白了,不知道对否。)
先说几个名词:变量对象,作用域,作用域链,函数执行环境
再说几个和变量有关的知识:变量值分为基本类型值和引用类型值,而基本类型的值的复制是直接拷贝副本,而引用类型只是拷贝地址。但是在给函数传参时,全部是按值传递的,就像基本类型值变量的复制一样。
我们来说列子。
当调用这个add_the_handlers函数时,把节点数组传递到这个函数执行环境中,这时的执行环境中有两个变量一个是I,另一个则是nodes.length,而这两个变量当add_the_handlers这个函数执行完毕,而且也没有函数或者其他变量引用这个两个值,他就会消失(这里是作用域的概念)。
但是当进入for循环后,当I为0的时间给节点0绑定上这个事件函数,也就是function(e){ alert(i); }这段代码,这里你要注意哦!这段代码没有人去调用,所以他不会执行,直到你触发这个节点为0的事件后这段代码才调用。所以当I值为1的时间同样给节点为1的绑定上一样的函数。直到节点数组的值绑定完。
这时这个add_the_handlers函数执行环境中的变量I值就变成了节点数目的值。但当我们去触发所有这些节点事件时,开始调用绑定的事件函数,而这个事件函数的执行环境中压根没有这个I变量值,他该怎么办,他根据作用域链的关系只有往上一级的执行环境寻找这个I的值。所以对于上级的执行环境也就是
add_the_handlers这个环境中的I值,有人在引用着他所以这个函数执行完毕I值不能消失而节点数可以消失,但是不能消失他保存在哪里了呢?实际上市保存在变量对象中(这个东西看不到,也不能调用),而这时的I值就是循环后的结果了,也就是节点数,所以当你不管点击那个节点弹出来的都是总节点的数目(也就是nodes.length的值)
经过改良的列子
var add_the = function (nodes){ var helper = function (i){ return function (e){ alert(i); } } var i; for(i = 0; i < nodes.length; i +=1){ nodes[i].onclick = helper(i); } }
当调用函数时,初始I值,给第0个节点绑定上这个函数helper(i),而这个I值根据函数传参的原理,会有一个同样的I值进入到helper这个执行环境中,而这个环境中返回出来的一个函数,在引用着helper这个函数执行环境中的变量I(因为返回出来的函数他没有I那个变量,只能往上级执行环境查找这个值),所以这个I值不会消失。其他同理
总结:
当一个函数内部被返回出来的函数,可以访问到他外部的函数执行环境中的变量或者对象,也就是说可以访问到他被创建时间的上下文环境,这就被称为闭包!我们这个例子中第二个例子helper()被称为闭包
闭包的特性:
1,闭包外层是个函数.
2,闭包内部都有函数.
3,闭包会return内部函数.
4,闭包返回的函数内部不能有return.(因为这样就真的结束了)
5,执行闭包后,闭包内部变量会存在,而闭包内部函数的内部变量不会存在.
闭包的应用场景
1、保护函数内的变量安全。
2、在内存中维持一个变量。
相关推荐
2. **作用域的详解**:解释不同类型的变量作用域,如全局作用域、局部作用域和块级作用域,并通过实例展示作用域规则。 3. **闭包的原理**:解释什么是闭包,如何创建闭包,以及闭包如何保持对外部变量的引用。 4....
### PHP中的变量作用域详解 #### 一、引言 在PHP编程中,理解变量作用域是非常重要的。正确的使用变量作用域能够帮助开发者避免一些常见的错误,同时也能够更好地利用PHP的一些高级特性来提高程序的可维护性和效率...
C#与闭包详解 在C#中,闭包是使用的变量已经脱离其作用域,却由于和作用域存在上下文关系,从而可以在当前环境中继续使用其上文环境中所定义的一种函数对象。下面将详细解释闭包的定义、变量作用域、变量的生命周期...
闭包和函数调用没多少相关,而是关于使用定义在其他作用域的变量 命名空间和作用域 我们把命名空间看做一个大型的字典类型(Dict),里面包含了所有变量的名字和值的映射关系。在 Python 中,作用域实际上可以看做是...
在JavaScript中,闭包提供了对变量作用域访问和数据持久化的能力。 在JavaScript中,作用域主要分为两种:全局作用域和局部作用域。全局作用域中的变量可在代码中任何地方被访问。局部作用域是指仅在函数内部声明的...
### JavaScript闭包详解 #### 一、什么是闭包? 闭包是JavaScript中一个重要的概念,它涉及函数如何访问外部作用域中的变量。虽然官方定义较为复杂:“闭包是一个拥有许多变量和绑定了这些变量的环境的表达式...
变量作用域的定义决定了变量可以被访问的区域,对于理解变量在不同上下文中的访问权限非常重要。 首先,我们要了解JavaScript中的变量有三种声明方式:使用var关键字、let关键字和const关键字。每种声明方式决定了...
闭包是一种特殊的作用域现象,它允许函数访问并操作其外部作用域的变量,即使在其外部作用域已被销毁后仍然保持对这些变量的引用。闭包在内存管理、数据封装和状态保持等方面有广泛应用。 **闭包的应用** 1. **延长...
### JavaScript闭包详解 #### 一、闭包概念与特性 **闭包**是JavaScript中最强大的特性之一,它指的是一个函数及其相关的引用环境的组合。简单来说,闭包就是一个能够记住并访问其自身作用域以外变量的函数。这种...
JavaScript中的闭包是一种强大的特性,它是理解JavaScript内存管理和作用域的关键。闭包允许函数访问和操作在其外部定义但在其内部引用的变量,即使在外部函数执行完毕后,这些变量仍然可访问。这是因为闭包保留了对...
JavaScript作用域是编程中至关重要的概念,它规定了变量和函数的可见性和生命周期。了解JavaScript作用域对于编写高效、安全的代码至关重要。本篇将详细解释JavaScript作用域的几个核心特性,包括无块级作用域、函数...
- **Enclosing**:如果在局部作用域找不到,会搜索任何包含当前作用域的非局部非全局的嵌套函数(闭包)。 - **Global**:接着搜索全局作用域,即模块级别的变量。 - **Built-in**:最后搜索内置命名空间,这里...
JavaScript中的闭包是一种高级特性,它允许一个函数访问并操作其外部作用域的变量,即使在外部函数已经执行完毕后。这种机制的核心在于,当内部函数引用了外部函数的变量时,JavaScript会保持对外部作用域的引用,...
从闭包的角度理解作用域链,就意味着内嵌函数不仅有自己作用域的变量,还能访问到外部函数作用域链上的变量。我们举一个例子来说明闭包的应用: ```javascript function bind(func, target) { return function() {...
本篇文章将详细介绍`for`循环中的变量作用域及其用法。 首先,我们来讨论`for`循环中的变量作用域。在Python中,`for`循环并不是一个独立的作用域,它的变量作用域与包含它的作用域相同。这意味着在循环内部定义的...
JavaScript中的闭包是一种重要的编程概念,它涉及到函数、作用域和变量持久化。闭包本质上是函数能够记住并访问其词法作用域内的变量,即使该函数已经执行完毕且其外部作用域不再存在。这种特性使得闭包成为...
在深入讨论JavaScript闭包之前,首先需要了解JavaScript的变量作用域。在JavaScript中,变量的作用域分为两种:全局变量和局部变量。全局变量是在函数外部定义的变量,可以在JavaScript程序的任何地方被访问。局部...
一、变量的作用域 在介绍闭包之前,我们先理解JavaScript的变量作用域。变量的作用域分为两种:全局变量和局部变量。 var n = 999; //全局变量 function f1() { a = 100; //在这里a也是全局变量 alert(n); }...