HTML代码中在两个匿名函数中使用同名变量出现bug而引起的变量作用域的思考

  在学习HTML的时候,为了方便地对同一个css样式的不同值的效果进行对比,我做成了下面这个样子。

代码也是很典型的用于展示的格式(p元素的内容随便写的):

 1 <head>
 2     <style>
 3         p{
 4             border: medium solid black;
 5             padding: 5px;
 6             margin: 5px;
 7             text-justify:inter-word;
 8         }
 9         button{
10             margin: 5px;
11         }
12     </style>
13 </head>
14 <body>
15     <p id="alignTest">
16         Visual Studio 使用模板创建项目。 C# .NET Core 控制台应用程序模板会自动定义类
17         Program 和一个需要将 String 数组用作自变量的方法 Main。 Main 是应用程序入口点,
18         同时也是在应用程序启动时由运行时自动调用的方法。 args 数组中包含在应用程序启动时提供的所有命令行自变量。
19     </p>
20
21     <button name="textAlign">start</button> <button name="textAlign">end</button>
22     <button name="textAlign">left</button> <button name="textAlign">right</button>
23     <button name="textAlign">center</button> <button name="textAlign">justify</button>
24
25     <script>
26         var buttons=document.getElementsByName("textAlign");
27         var target=document.getElementById("alignTest");
28         for(var i=0;i<buttons.length;i++){
29             buttons[i].onclick=function(e){
30                 target.style.textAlign=e.target.innerHTML;
31             }
32         }
33     </script>
34
35     <p id="white">
36         在“添加新项目”对话框中,展开“Visual C#”节点,并依次选择“.NET Standard”节点和“类库(.NET Standard)”项目模板。
37         在“名称”文本框中,输入项目名称“StringLibrary”。 选择“确定”,创建类库项目。然后,代码窗口在 Visual Studio 开发环境中打开。
38         请检查以确保库定目标到 .NET Standard 的正确版本。 右键单击“解决方案资源管理器”窗口中的库项目,再选择“属性”。 “目标框架”文本框显示定目标到 .NET Standard 2.0。
39     </p>
40     <div id="wh">
41         <button >normal</button ><button id="nor">nowrap</button><button>pre</button>
42         <button>pre-line</button><button>pre-wrap</button>
43     </div>
44     <script>
45         var whites=document.getElementById("wh").getElementsByTagName("button");
46         var target=document.getElementById("white");
47         for(var i=0;i<whites.length;i++){
48             whites[i].onclick=function(e){
49                 target.style.whiteSpace=e.target.innerHTML;
50             }
51         }
52     </script>
53 </body>

但当我在点击上面的按钮时,改变的确是下面的p元素的样式:

我仔细地检查了代码,我所声明的全部都是局部变量,那么问题出现在哪里呢?

然后我回想起了c#使用匿名函数的时候,由于闭包特性,变量会在调用才赋值,导致结果与期望不一致,然后我返回这段代码,把目光锁定到了下列代码上:

27         var target=document.getElementById("alignTest");
28         for(var i=0;i<buttons.length;i++){
29             buttons[i].onclick=function(e){
30                 target.style.textAlign=e.target.innerHTML;
31             }
32         }
46         var target=document.getElementById("white");
47         for(var i=0;i<whites.length;i++){
48             whites[i].onclick=function(e){
49                 target.style.whiteSpace=e.target.innerHTML;
50             }
51         }

我在这里声明了两个target变量,难道这个target也是在调用时才赋值?

于是我将下面的变量名target修改成了target1,最后代码如下:

<head>
    <style>
        p{
            border: medium solid black;
            padding: 5px;
            margin: 5px;
            text-justify:inter-word;
        }
        button{
            margin: 5px;
        }
    </style>
</head>
<body>
    <p id="alignTest">
        Visual Studio 使用模板创建项目。 C# .NET Core 控制台应用程序模板会自动定义类
        Program 和一个需要将 String 数组用作自变量的方法 Main。 Main 是应用程序入口点,
        同时也是在应用程序启动时由运行时自动调用的方法。 args 数组中包含在应用程序启动时提供的所有命令行自变量。
    </p>

    <button name="textAlign">start</button> <button name="textAlign">end</button>
    <button name="textAlign">left</button> <button name="textAlign">right</button>
    <button name="textAlign">center</button> <button name="textAlign">justify</button>

    <script>
        var buttons=document.getElementsByName("textAlign");
        var target=document.getElementById("alignTest");
        for(var i=0;i<buttons.length;i++){
            buttons[i].onclick=function(e){
                target.style.textAlign=e.target.innerHTML;
            }
        }
    </script>

    <p id="white">
        在“添加新项目”对话框中,展开“Visual C#”节点,并依次选择“.NET Standard”节点和“类库(.NET Standard)”项目模板。
        在“名称”文本框中,输入项目名称“StringLibrary”。 选择“确定”,创建类库项目。然后,代码窗口在 Visual Studio 开发环境中打开。
        请检查以确保库定目标到 .NET Standard 的正确版本。 右键单击“解决方案资源管理器”窗口中的库项目,再选择“属性”。 “目标框架”文本框显示定目标到 .NET Standard 2.0。
    </p>
    <div id="wh">
        <button >normal</button ><button id="nor">nowrap</button><button>pre</button>
        <button>pre-line</button><button>pre-wrap</button>
    </div>
    <script>
        var whites=document.getElementById("wh").getElementsByTagName("button");
        var target1=document.getElementById("white");
        for(var i=0;i<whites.length;i++){
            whites[i].onclick=function(e){
                target1.style.whiteSpace=e.target.innerHTML;
            }
        }
    </script>
</body>

终于在我点击了上面的按钮后更改的为第一个p的样式

由此我得知了在js中匿名函数的变量也是在调用时才赋值,但我不禁在想为什么我声明了两个局部变量后后面的局部变量会覆盖前边的局部变量,除非我声明的其实是同一个变量,即我在这里声明的变量的作用域与我之前接触的语言不一样的。

在查阅了资料后我得知了js没有块级作用域的特性和闭包特性。https://blog.csdn.net/u012896140/article/details/49494785

在我看来,没有块级作用域即代表着我所声明的target变量不像之前在c#声明的一样——不会有隐藏的特定前缀来指定该变量为独一无二的变量;而这一特性联合上闭包特性则使我之前声明的变量由于生存期被延长最后被第二个声明的target变量所替换,最后在调用上面button的onclick事件时则使用的是后面生成的变量。

原文地址:https://www.cnblogs.com/gokoururi/p/9686009.html

时间: 2024-10-08 08:49:55

HTML代码中在两个匿名函数中使用同名变量出现bug而引起的变量作用域的思考的相关文章

js闭包中的this(匿名函数中的this指向的是windows)

1.普通函数中的this指向的是对象,匿名函数中的this指向的是windows,和全局变量一样 2.让匿名函数中的this指向对象的两种方法 可以使用对象冒充强制改变this:call().apply()        将this赋值给一个变量,闭包可以访问这个变量 一.this问题 匿名函数的执行环境具有全局性,因此其this对象通常指向window(当然,在通过call()或者apply()改变函数执行环境的情况下,this就会指向其他对象) 为什么匿名函数没有取得其包含作用域(或外部作用

JavaScript中的闭包与匿名函数

知识内容: 1.预备知识 - 函数表达式 2.匿名函数 3.闭包 一.函数表达式 1.定义函数的两种方式 函数声明: 1 function func(arg0, arg1, arg2){ 2 // 函数体 3 } 函数表达式: 1 var func = function (arg0, arg1, arg2){ 2 // 函数体 3 } 2.注意事项 函数表达式使用前必须赋值!像下面的代码是错误的: 1 say() 2 var say = function(){ 3 console.log("12

avascript中的自执行匿名函数

Javascript中的自执行匿名函数 格式: (function(){ //代码 })(); 解释:这是相当优雅的代码(如果你首次看见可能会一头雾水:)),包围函数(function(){})的第一对括号向脚本返回未命名的函数,随后一对空括号立即执行返回的未命名函数,括号内为匿名函数的参数. 来个带参数的例子: (function(arg){ alert(arg+100); })(20); // 这个例子返回120. 重要用途:可以用它创建命名空间,只要把自己所有的代码都写在这个特殊的函数包装

PHP中的闭包和匿名函数

PHP中的闭包和匿名函数 闭包是指在创建时封装周围状态的函数.即使闭包所在的环境不存在了,闭包中封装的状态依然存在. 匿名函数就是没有名称的函数.匿名函数可以赋值给变量,还能像其他任何PHP对象那样传递.不过匿名函数仍是函数,因此可以调用,还可以传入参数.匿名函数特别适合作为函数或方法的回调. 注意:理论上讲,闭包和匿名函数是不同的概念.不过,PHP将其视作相同的概念.所以,我们提到闭包时,指的也是匿名函数,反之亦然. PHP闭包和匿名函数使用的句法与普通函数相同,但闭包和匿名函数其实是伪装成函

浅析PHP中的闭包和匿名函数

PHP闭包和匿名函数使用的句法与普通函数相同,但闭包和匿名函数其实是伪装成函数的对象(Closure类的实例) .下面给大家介绍PHP中的闭包和匿名函数知识,需要的朋友参考下吧 闭包是指在创建时封装周围状态的函数.即使闭包所在的环境不存在了,闭包中封装的状态依然存在. 匿名函数就是没有名称的函数.匿名函数可以赋值给变量,还能像其他任何PHP对象那样传递.不过匿名函数仍是函数,因此可以调用,还可以传入参数.匿名函数特别适合作为函数或方法的回调. 注意:理论上讲,闭包和匿名函数是不同的概念.不过,P

Python递归列出目录中文件脚本及其匿名函数

1.递归列出目录里的文件的脚本举例 列出目录中的文件可以通过下面方法:os.listdir() In [1]: import os In [4]: os.listdir('/root') Out[4]: ['.tcshrc', '.bash_history', '.bashrc', 'ENV', '.cache', '.config', '.cshrc', '.bash_logout', 'python', '.ssh', 'shell', '.bash_profile', '.ipython'

关于js中立即执行的匿名函数写法

1 /*最流行的写法*/ 2 (function() { 3 alert("run!") 4 })(); 5 6 /* !号可以有1~正无穷个,所以这一种就可以衍生无数种方式 */ 7 !!!(function() { 8 alert("run!") 9 })(); 10 11 (function() { 12 alert("run!") 13 }).call(); 14 15 (function() { 16 alert("run!&

Javascript中的自执行匿名函数(个人理解也叫立即执行的匿名函数)的理解

格式: (function(){ //代码 })(); 包围函数(function(){})的第一对括号向脚本返回未命名的函数,随后一对空括号立即执行返回的未命名函数,括号内为匿名函数的参数. (function(arg){ alert(arg+100); })(20); // 这个例子返回120. 回来看看jquery的插件编写 (function($) { // Code goes here })(jQuery); 这样代码等同于 var a=functon($) {//code }; a(

php 在 匿名函数中 调用自身。。

//php闭包实现函数的自调用,也就是实现递归 function closure($n,$counter,$max){ //匿名函数,这里函数的参数加&符号是,引址调用参数自己 $fn = function (&$n,&$counter,&$max=1) use(&$fn){//use参数传递的是函数闭包函数自身 $n++; if($n < $max){//递归点,也就是递归的条件 $counter .=$n.'<br />'; //递归调用自己