zoukankan      html  css  js  c++  java
  • javascript的变量作用域--对比js、php和c的for循环

    为什么要写这篇文章呢?主要是给自己提个醒,js的水很深,需要小心点儿才能趟过去,更何况自己不是专业人士,那就得更加小心了。

    看下面的js代码:

     1 <!DOCTYPE html>
     2 <html>
     3   <head>
     4     <meta charset="utf-8">
     5     <title>javascript中变量的作用域</title>
     6   </head>
     7   <body>
     8 
     9   <script>
    10   for (var i = 0; i < 3; i++) {
    11     console.log(i);
    12   }
    13   console.log('第一个for循环结束');
    14   console.log(i);
    15 
    16   console.log('第二个for循环开始');
    17 
    18   for (; i > 0; i--) {
    19     console.log(i);
    20   }
    21     console.log('第二个for循环结束');
    22   console.log(i);
    23   </script>
    24   </body>
    25 </html>

    你猜它的输出是什么?

    为何循环结束后,i的值仍然存在呢?js循环代码块内部变量的作用域怎么跑到外面来了?作为js小白的我,竟然会问这么傻的问题。答案是,js没有块级作用域,像for、if、switch等控制结构形成的代码块内部声明的变量其实都是全局变量。对于像c这种有块级作用域的语言,在for语句执行完毕后,循环变量会被销毁,下面是c语言的for循环:

    1 #include "stdio.h"
    2 
    3 int main() {
    4     for (int i = 0; i < 3; i++) {
    5         printf("%d
    ", i);
    6     }
    7 
    8     printf("%d
    ", i); // 这里编译时会报错 error: use of undeclared identifier 'i'
    9 }

    编译时报错如下:

    而对于javascript这种没有块级作用域的语言,即使在for循环结束之后,循环变量i也是会存在于循环外部的“全局”当中,因为这个循环变量其实就是“全局变量”。这种描述不够准确,javascript当中一个重要的概念是执行环境(execution context),简称环境。每个环境都有一个与之关联的变量对象,环境中定义的所有变量和函数都保存在这个对象中。全局执行环境是最外围的一个执行环境,比如在浏览器中,全局执行环境就是window对象,所以,所有的全局变量都是作为window对象的属性和方法创建的。比如上面的循环变量i,应该可以访问window.i:

    下面只写出js代码:

     1   for (var i = 0; i < 3; i++) {
     2     console.log(i);
     3   }
     4   console.log('第一个for循环结束');
     5   console.log(i);
     6   console.log('访问window.i');
     7   console.log(window.i);
     8   
     9   console.log('第二个for循环开始');
    10 
    11   for (; i > 0; i--) {
    12     console.log(i);
    13   }
    14     console.log('第二个for循环结束');
    15   console.log(i);
    16 
    17   console.log('访问window.i');
    18   console.log(window.i);

    结果如下:

    那么,javascript中的局部变量该怎么定义呢?(或者说如何定义一个变量,这个变量不会被影响到全局呢),答案是函数。js中除了全局执行环境外,还有一个执行环境:函数执行环境,也可以把它叫做局部执行环境。比如下面这段代码:

    1   var j = 0;
    2   function test() {
    3     var j = 1;
    4     return j;
    5   }
    6 
    7   console.log(j);

    输出结果为0,证明函数内部的j没有污染到外部的j,函数内部的j只在函数的执行环境内被访问。

    我又想到php跟js一样都是脚本语言,那么php是不是也没有块级作用域呢?看下面的代码:

     1 <?php
     2 
     3 if (true) {
     4     $i = 7;
     5 }
     6 echo $i , PHP_EOL;
     7 
     8 for ($i = 0; $i < 3; $i++) {
     9     echo $i , PHP_EOL;
    10 }
    11 echo '第一个for循环结束' , PHP_EOL;
    12 echo $i , PHP_EOL;
    13 
    14 echo '第二个for循环开始' , PHP_EOL;
    15 for (; $i > 0; $i--) {
    16     echo $i , PHP_EOL;
    17 }
    18 echo '第二个for循环结束' , PHP_EOL;
    19 
    20 echo $i , PHP_EOL;

    输出结果如下:

    嗯,没错,它也没有块级作用域。其实php手册中很“含蓄”的表达了这一点:“变量的范围即它定义的上下文背景(也就是它的生效范围)。大部分的 PHP 变量只有一个单独的范围。这个单独的范围跨度同样包含了 include 和 require 引入的文件。......在用户自定义函数中,一个局部函数范围将被引入。任何用于函数内部的变量按缺省情况将被限制在局部函数范围内。”

    我又想到了php的for循环,我记得php手册中对于foreach循环的描述中有这么一段话“Warning:数组最后一个元素的 $value 引用在 foreach 循环之后仍会保留。建议使用 unset() 来将其销毁。”,这个恐怕也是因为它没有块级作用域的原因,但手册中for循环中没有提到这一点,这有些奇怪。看来,php的水也很深。

    其实,javascript的ES6规范中已经引入了let(还有const)变量标识符,利用let可以让js的变量拥有块级作用域,看下面的代码:

    1   for (let i = 0; i < 3; i++) {
    2     console.log(i);
    3   }
    4   console.log('第一个for循环结束');
    5   console.log(i);

    输出结果如下:

    看来js正在变得越来越规范。

    ps:js的执行环境、php的局部变量和全局变量,以后还要仔细学习下。

    参考:

    1,javascript高级程序设计

    2,php手册

  • 相关阅读:
    生成一个四位数的随机验证码
    计算阶乘
    四种排序(冒泡、插入、递归、选择)
    Java基础面试被常问到知识点
    Qt中的坐标系统
    a message box to confirm the action
    点击按钮退出窗口
    为部件提供浮动提示信息
    在窗口标题栏的左上方显示图标
    PyQt5显示一个空白的窗口
  • 原文地址:https://www.cnblogs.com/yangtoude/p/js-variable-scope-php-c-for-loop.html
Copyright © 2011-2022 走看看