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

看下面的js代码:

 <!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>javascript中变量的作用域</title>
</head>
<body> <script>
for (var i = 0; i < 3; i++) {
console.log(i);
}
console.log('第一个for循环结束');
console.log(i); console.log('第二个for循环开始'); for (; i > 0; i--) {
console.log(i);
}
console.log('第二个for循环结束');
console.log(i);
</script>
</body>
</html>

你猜它的输出是什么?

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

 #include "stdio.h"

 int main() {
for (int i = ; i < ; i++) {
printf("%d\n", i);
} printf("%d\n", i); // 这里编译时会报错 error: use of undeclared identifier 'i'
}

编译时报错如下:

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

下面只写出js代码:

   for (var i = 0; i < 3; i++) {
console.log(i);
}
console.log('第一个for循环结束');
console.log(i);
console.log('访问window.i');
console.log(window.i); console.log('第二个for循环开始'); for (; i > 0; i--) {
console.log(i);
}
console.log('第二个for循环结束');
console.log(i); console.log('访问window.i');
console.log(window.i);

结果如下:

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

   var j = 0;
function test() {
var j = 1;
return j;
} console.log(j);

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

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

 <?php

 if (true) {
$i = 7;
}
echo $i , PHP_EOL; for ($i = 0; $i < 3; $i++) {
echo $i , PHP_EOL;
}
echo '第一个for循环结束' , PHP_EOL;
echo $i , PHP_EOL; echo '第二个for循环开始' , PHP_EOL;
for (; $i > 0; $i--) {
echo $i , PHP_EOL;
}
echo '第二个for循环结束' , PHP_EOL; echo $i , PHP_EOL;

输出结果如下:

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

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

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

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

输出结果如下:

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

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

参考:

1,javascript高级程序设计

2,php手册

javascript的变量作用域--对比js、php和c的for循环的更多相关文章

  1. [转]深入理解JavaScript的变量作用域

    1.JavaScript的作用域链 2.函数体内部,局部变量的优先级比同名的全局变量高. 3.JavaScript没有块级作用域. 4.函数中声明的变量在整个函数中都有定义. 5.未使用var关键字定 ...

  2. 深入理解JavaScript的变量作用域(转载Rain Man之作)

    在学习JavaScript的变量作用域之前,我们应当明确几点: JavaScript的变量作用域是基于其特有的作用域链的. JavaScript没有块级作用域. 函数中声明的变量在整个函数中都有定义. ...

  3. 深入理解JavaScript的变量作用域

    在学习JavaScript的变量作用域之前,我们应当明确几点: JavaScript的变量作用域是基于其特有的作用域链的. JavaScript没有块级作用域. 函数中声明的变量在整个函数中都有定义. ...

  4. JavaScript函数变量作用域

    变量作用域 在JavaScript中,用var申明的变量实际上是有作用域的. 如果一个变量在函数体内部申明,则该变量的作用域为整个函数体,在函数体外不可引用该变量. 如果两个不同的函数各自申明了同一变 ...

  5. Javascript之变量作用域

    分析: 无论是强类型语言c#.c++.java等语言,还是弱类型语言如Javascript,所有变量可以抽象为两种类型,即局部变量和全局变量. 全局变量:整个作用域可见. 局部变量:局部可见,退出作用 ...

  6. JavaScript的变量作用域

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  7. 浅谈javascript中变量作用域和内存(1)

    先理解两个概念:基本类型和引用类型的值 1.基本类型和引用类型的值 (1)定义: 基本类型:指简单的数据段,比如按值访问的js五种基本数据类型undefined.null.boolean.number ...

  8. 浅谈javascript中变量作用域和内存(2)

    1.无块级作用域 javascript没有块级作用域,这会让其他程序员在理解js代码上很痛苦.在其他很多语言,比如C,大括号括起来的代码块都有自己的作用域 举个例子 if(true) { var na ...

  9. JavaScript 关于变量作用域的一道面试题

    ShineJaie 原创,转载请注明出处. 昨晚在一个交流群里看到有位网友提了一个他的面试题求助答疑.刚好我也有看到,就对这个问题思考了一下,觉得这道题对理解 JavaScript 作用域还是很有帮助 ...

随机推荐

  1. js学习笔记:操作iframe

    iframe可以说是比较老得话题了,而且网上也基本上在说少用iframe,其原因大致为:堵塞页面加载.安全问题.兼容性问题.搜索引擎抓取不到等等,不过相对于这些缺点,iframe的优点更牛,跨域请求. ...

  2. 几个有趣的WEB设备API(二)

    浏览器和设备之间还有很多有趣的接口, 1.屏幕朝向接口 浏览器有两种方法来监听屏幕朝向,看是横屏还是竖屏. (1)使用css媒体查询的方法 /* 竖屏 */ @media screen and (or ...

  3. 隐私泄露杀手锏 —— Flash 权限反射

    [简版:http://weibo.com/p/1001603881940380956046] 前言 一直以为该风险早已被重视,但最近无意中发现,仍有不少网站存在该缺陷,其中不乏一些常用的邮箱.社交网站 ...

  4. ASP.NET Aries 入门开发教程2:配置出一个简单的列表页面

    前言: 朋友们都期待我稳定地工作,但创业公司若要躺下,也非意念可控. 若人生注定了风雨飘摇,那就雨中前行了. 最机开始看聊新的工作机会,欢迎推荐,创业公司也可! 同时,趁着自由时间,抓紧把这系列教程给 ...

  5. C语言 · 矩阵乘法 · 算法训练

    问题描述 输入两个矩阵,分别是m*s,s*n大小.输出两个矩阵相乘的结果. 输入格式 第一行,空格隔开的三个正整数m,s,n(均不超过200). 接下来m行,每行s个空格隔开的整数,表示矩阵A(i,j ...

  6. 算法与数据结构(十七) 基数排序(Swift 3.0版)

    前面几篇博客我们已经陆陆续续的为大家介绍了7种排序方式,今天博客的主题依然与排序算法相关.今天这篇博客就来聊聊基数排序,基数排序算法是不稳定的排序算法,在排序数字较小的情况下,基数排序算法的效率还是比 ...

  7. 解读发布:.NET Core RC2 and .NET Core SDK Preview 1

    先看一下 .NET Core(包含 ASP.NET Core)的路线图: Beta6: 2015年7月27日 Beta7: 2015年9月2日 Beta8: 2015年10月15日 RC1: 2015 ...

  8. Android 几种消息推送方案总结

    转载请注明出处:http://www.cnblogs.com/Joanna-Yan/p/6241354.html 首先看一张国内Top500 Android应用中它们用到的第三方推送以及所占数量: 现 ...

  9. 微软发布VSBT,无需安装Visual Studio即可实现项目编译

    安装了Visual Studio的那些使用微软平台的开发者通常能够非常容易地操作自己的项目:打开解决方案,修改内容,设置好所有必须的文件以及配置后编译项目.但是在构建服务器或者持续交付系统等没有安装V ...

  10. Android SDK 在线更新镜像服务器资源

    本文转自:http://blog.kuoruan.com/24.html.感谢原作者. 什么是Android SDK SDK:(software development kit)软件开发工具包.被软件 ...