Maison interface Web js tutoriel JavaScript 变量作用域及闭包_javascript技巧

JavaScript 变量作用域及闭包_javascript技巧

May 16, 2016 pm 06:48 PM
javascript 作用域 变量 闭包

作用域JavaScript 的变量作用域是按照函数划分的,为了快速的了解它的特性,我们通过实例来进行演示。

实例一: 

<script type="text/javascript"> 
var i = 1; 
// 弹出内容为 1 true 的提示框 
alert(window.i + &#39; &#39; + (window.i == i)); 
</script>
Copier après la connexion

分析:
在全局定义的变量其实就是 window 对象的属性。
上面的例子可以看到,我们定义全局变量的同时,window 对象会产生一个相应的属性,如何让我们的代码避免产生这个属性呢,看下面的例子。
实例二:

<script type="text/javascript"> 
var document = 1; 
window.onload = function(){ 
alert(document); 
} 
// 弹出内容为 1 的提示框 
alert(window.document); 
</script>
Copier après la connexion

这种情况是我们不想看到的,我们可以这么做:

<script type="text/javascript"> 
function test(){ 
var document = 1; 
window.onload = function(){ 
alert(document); 
} 
} 
test(); 
// 弹出内容为 [object] 的提示框 
alert(window.document); 
</script>
Copier après la connexion

为了使代码更加简洁,我们可以这样:

<script type="text/javascript"> 
(function(){ 
var document = 1; 
window.onload = function(){ 
alert(document); 
} 
})(); 
// 弹出内容为 [object] 的提示框 
alert(window.document); 
</script>
Copier après la connexion

分析:
这种运行匿名方法的形式,在 JavaScript 的主流框架中经常见到,这样做可以避免产生不必要的 window 对象的属性,减少冲突的可能。
实例三:

<script type="text/javascript"> 
(function(){ 
if(&#39;1&#39; == &#39;1&#39;){ 
var i = 1; 
} 
// 弹出内容为 1 的提示框 
alert(i); 
})(); 
</script>
Copier après la connexion

分析:
变量的作用域是整个函数,不是{}块。
实例四:

<script type="text/javascript"> 
var i = 1; 
// 弹出内容为 1 的提示框 
alert(i); 
var i = 2; 
// 弹出内容为 2 的提示框 
alert(i); 
</script>
Copier après la connexion


分析:
一个变量可以被重新定义,这个看起来有些怪,因为在很多其他语言里这样是行不通的。
实例五:

<script type="text/javascript"> 
function test(){ 
i = 1; 
} 
test(); 
// 弹出内容为 1 的提示框 
alert(window.i); 
</script>
Copier après la connexion

分析:
如果对一个没有初始化的变量进行赋值操作,那么这个变量会作为全局变量。

实例六:

<script type="text/javascript"> 
window.onload = function(){ 
var i = 1; 
function test(){ 
alert(i); 
} 
// 弹出内容为 1 的提示框 
test(); 
} 
</script>
Copier après la connexion

分析:
内部函数可以访问外部函数的变量,这个就引出了一个新的概念,那就是闭包。
闭包
什么是闭包呢,简单的说就是一个函数 A ,它的内部函数 B 可以访问 A 内定义的变量,即使函数 A 已经终止。下面通过实例进行了解。
实例七:

<script type="text/javascript"> 
window.onload = function(){ 
var i = 1; 
window.onunload = function(){ 
alert(i); 
} 
} 
</script>
Copier après la connexion

分析:
当整个页面加载完成时,会触发 onload 事件,这个onload 事件方法里给窗口的onunload 事件注册了一个方法,这个方法里用到了onload 事件方法里声明的变量,然后onload 事件方法运行结束,这时候我们点击关闭窗口,会弹出内容为1的提示框,说明onunload 的事件方法成功的调用了onload 事件方法里声明的变量。
为了进一步了解闭包的特性,看下面的例子
实例八:

<script type="text/javascript"> 
function initX(oarg){ 
// 定义一个变量 
var x = oarg; 
// 定义一个显示变量的方法 
var funGet = function(){ 
alert(x); 
} 
// 定义一个对变量进行修改的方法 
var funSet = function(iarg){ 
x = iarg; 
} 
// 返回这两个方法 
return [funGet,funSet]; 
} 
// 运行一个方法实例,返回值为包含 get 和 set 方法的数组 
var funArr = initX(1); 
// 得到 get 方法 
var funGet = funArr[0]; 
// 得到 set 方法 
var funSet = funArr[1]; 
// 运行 get 方法,显示initX方法实例内的 x 变量,结果为 1 
funGet(); 
// 运行 set 方法,对initX方法实例内的 x 变量进行赋值 
funSet(2); 
// 运行 get 方法,显示initX方法实例内的 x 变量,结果为 2 
funGet(); 
</script>
Copier après la connexion

分析:
当内部函数对外部函数定义的变量进行调用时,实际上引用的是这个变量的内存块,所以当我们调用内部函数时,引用的变量值是当前这个变量的实际内容。
闭包功能虽然强大,但是如果不注意,它也会给我们带来困扰。看下面的例子。
实例九:

<button id="main">run</button> 
<script type="text/javascript"> 
(function(){ 
var obj = document.getElementById("main"); 
var funArr = [&#39;onclick&#39;,&#39;onkeypress&#39;]; 
for(var i=0; i<funArr.length; i++){ 
var temp = funArr[i]; 
obj[temp] = function(){ 
alert(temp); 
} 
} 
})(); 
</script>
Copier après la connexion

写代码的原意是给 id 是 main 的按钮注册点击事件和按键事件,事件的内容是分别弹出事件名称的提示框。但是结果有点匪夷所思,两个事件的提示框全是 onkeypress,根据闭包的原理,我们仔细分析,就会发现当两个事件方法被调用时 temp 变量 指向的是 funArr[1] 的内容,我们可以这样修改来解决这个问题:

<button id="main">run</button> 
<script type="text/javascript"> 
(function(){ 
var obj = document.getElementById("main"); 
var funArr = [&#39;onclick&#39;,&#39;onkeypress&#39;]; 
for(var i=0; i<funArr.length; i++){ 
(function(){ 
var temp = funArr[i]; 
obj[temp] = function(){ 
alert(temp); 
} 
})(); 
} 
})(); 
</script>
Copier après la connexion

把 for 循环内的代码放入一个函数内,这样,每循环一次都会产生一个函数实例,让函数实例记录 funArr 数组中的每个值,这样就避免了上面碰到的问题。

Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn

Outils d'IA chauds

Undresser.AI Undress

Undresser.AI Undress

Application basée sur l'IA pour créer des photos de nu réalistes

AI Clothes Remover

AI Clothes Remover

Outil d'IA en ligne pour supprimer les vêtements des photos.

Undress AI Tool

Undress AI Tool

Images de déshabillage gratuites

Clothoff.io

Clothoff.io

Dissolvant de vêtements AI

AI Hentai Generator

AI Hentai Generator

Générez AI Hentai gratuitement.

Article chaud

R.E.P.O. Crystals d'énergie expliqués et ce qu'ils font (cristal jaune)
2 Il y a quelques semaines By 尊渡假赌尊渡假赌尊渡假赌
Repo: Comment relancer ses coéquipiers
4 Il y a quelques semaines By 尊渡假赌尊渡假赌尊渡假赌
Hello Kitty Island Adventure: Comment obtenir des graines géantes
4 Il y a quelques semaines By 尊渡假赌尊渡假赌尊渡假赌
Combien de temps faut-il pour battre Split Fiction?
3 Il y a quelques semaines By DDD

Outils chauds

Bloc-notes++7.3.1

Bloc-notes++7.3.1

Éditeur de code facile à utiliser et gratuit

SublimeText3 version chinoise

SublimeText3 version chinoise

Version chinoise, très simple à utiliser

Envoyer Studio 13.0.1

Envoyer Studio 13.0.1

Puissant environnement de développement intégré PHP

Dreamweaver CS6

Dreamweaver CS6

Outils de développement Web visuel

SublimeText3 version Mac

SublimeText3 version Mac

Logiciel d'édition de code au niveau de Dieu (SublimeText3)

Utilisation de la structure typedef en langage C Utilisation de la structure typedef en langage C May 09, 2024 am 10:15 AM

typedef struct est utilisé en langage C pour créer des alias de type de structure afin de simplifier l'utilisation des structures. Il crée un alias pour un nouveau type de données sur une structure existante en spécifiant l'alias de la structure. Les avantages incluent une lisibilité améliorée, la réutilisation du code et la vérification du type. Remarque : La structure doit être définie avant d'utiliser un alias. L'alias doit être unique dans le programme et valide uniquement dans le périmètre dans lequel il est déclaré.

Comment résoudre la variable attendue en Java Comment résoudre la variable attendue en Java May 07, 2024 am 02:48 AM

Les exceptions de valeur attendue des variables en Java peuvent être résolues en : initialisant les variables ; en utilisant des valeurs par défaut ; en utilisant des contrôles et des affectations et en connaissant la portée des variables locales ;

Avantages et inconvénients des fermetures en js Avantages et inconvénients des fermetures en js May 10, 2024 am 04:39 AM

Les avantages des fermetures JavaScript incluent le maintien d'une portée variable, l'activation du code modulaire, l'exécution différée et la gestion des événements ; les inconvénients incluent les fuites de mémoire, la complexité accrue, la surcharge de performances et les effets de chaîne de portée.

Que signifie inclure en C++ Que signifie inclure en C++ May 09, 2024 am 01:45 AM

La directive de préprocesseur #include en C++ insère le contenu d'un fichier source externe dans le fichier source actuel, en copiant son contenu à l'emplacement correspondant dans le fichier source actuel. Principalement utilisé pour inclure des fichiers d'en-tête contenant les déclarations nécessaires dans le code, telles que #include <iostream> pour inclure des fonctions d'entrée/sortie standard.

Comment implémenter la fermeture dans une expression C++ Lambda ? Comment implémenter la fermeture dans une expression C++ Lambda ? Jun 01, 2024 pm 05:50 PM

Les expressions C++ Lambda prennent en charge les fermetures, qui enregistrent les variables de portée de fonction et les rendent accessibles aux fonctions. La syntaxe est [capture-list](parameters)->return-type{function-body}. capture-list définit les variables à capturer. Vous pouvez utiliser [=] pour capturer toutes les variables locales par valeur, [&] pour capturer toutes les variables locales par référence, ou [variable1, variable2,...] pour capturer des variables spécifiques. Les expressions Lambda ne peuvent accéder qu'aux variables capturées mais ne peuvent pas modifier la valeur d'origine.

Pointeurs intelligents C++ : une analyse complète de leur cycle de vie Pointeurs intelligents C++ : une analyse complète de leur cycle de vie May 09, 2024 am 11:06 AM

Cycle de vie des pointeurs intelligents C++ : Création : Les pointeurs intelligents sont créés lors de l'allocation de mémoire. Transfert de propriété : Transférer la propriété via une opération de déménagement. Libération : la mémoire est libérée lorsqu'un pointeur intelligent sort de la portée ou est explicitement libéré. Destruction d'objet : lorsque l'objet pointé est détruit, le pointeur intelligent devient un pointeur invalide.

Il existe plusieurs situations dans lesquelles cela indique en js Il existe plusieurs situations dans lesquelles cela indique en js May 06, 2024 pm 02:03 PM

En JavaScript, les types de pointage de this incluent : 1. Objet global ; 2. Appel de fonction ; 3. Appel de constructeur 4. Gestionnaire d'événements 5. Fonction de flèche (héritant de this). De plus, vous pouvez définir explicitement ce que cela désigne à l'aide des méthodes bind(), call() et apply().

Les définitions de fonctions et les appels en C++ peuvent-ils être imbriqués ? Les définitions de fonctions et les appels en C++ peuvent-ils être imbriqués ? May 06, 2024 pm 06:36 PM

Peut. C++ autorise les définitions et les appels de fonctions imbriquées. Les fonctions externes peuvent définir des fonctions intégrées et les fonctions internes peuvent être appelées directement dans la portée. Les fonctions imbriquées améliorent l'encapsulation, la réutilisabilité et le contrôle de la portée. Cependant, les fonctions internes ne peuvent pas accéder directement aux variables locales des fonctions externes et le type de valeur de retour doit être cohérent avec la déclaration de la fonction externe. Les fonctions internes ne peuvent pas être auto-récursives.

See all articles