变量作用域

在JavaScript中,用var申明的变量实际上是有作用域的。

如果一个变量在函数体内部申明,则该变量的作用域为整个函数体,在函数体外不可引用该变量。

如果两个不同的函数各自申明了同一变量,那么该变量只在各自的函数体内起作用。换句话说,不同函数内部的同名变量互相独立,互不影响。

由于JavaScript的函数可以嵌套,此时,内部函数可以访问外部函数定义的变量,反过来则不行:

    function foo() {
var x = 1;
function bar() {
var y = x + 1 ;//bar可以访问foo的变量x
}
var z = y + 1;//ReferenceError!foo不可以访问bar的变量y!
}

如果内部函数和外部函数的变量名重名怎么办?

    function foo() {
var x = 1;
function bar() {
var x = 'A';
alert('x in bar() =' + x);//'A'
}
alert('x in foo() =' + x );//
bar();
}

JavaScript的函数在查找变量时从自身函数定义开始,从“内”向“外”查找。如果内部函数定义了与外部函数重名的变量,则内部函数的变量将“屏蔽”外部函数的变量。

变量提升

JavaScript的函数定义有个特点,它会先扫描整个函数体的语句,把所有申明的变量“提升”到函数顶部:

    function foo() {
var x = "Hello," + y ;
alert(x);
var y = "Bob";
} foo();//Hello,undefined

语句 var x = "Hello," + y ;并不会报错,原因是变量y在稍后申明了。但是alert显示的是Hello,undefined,说明变量y的值是undefined,这正是因为JavaScript引擎自动提升了变量y的声明,但是不会提升变量y的赋值语句。

对于上述的foo()函数,JavaScript引擎看到的代码相当于:

          function foo() {
var y;//提升变量y的申明
var x = 'Hello,' + y ;
alert(x);
y='Bob';
}

tips:所以在JavaScript函数内部要首先申明所有变量。最常见的做法是用一个var申明函数内部用到的所有变量:

    function foo() {
var
x=1,//x初始化为1
y=x+1,//y初始化为2
z,i;//z和i为undefined
//其他语句
for(i = 0; i<100; i++){
...
}
}

全局作用域

不在任何函数内定义的变量就具有全局作用域。JavaScript默认有一个全局对象window,全局作用域的变量实际上被绑定到window的一个属性:

     var course = 'Learn JavaScript';
alert(course);//'Learn JavaScript'
alert(window.course);//'Learn JavaScript'

因此,直接访问全局变量course和访问window.course是完全一样的。

由于函数定义有两种方式,以变量方式var foo = function () {}定义的函数实际上也是一个全局变量。因此,顶层函数的定义也被视为一个全局变量

名字空间

全局变量会绑定到window上,不同的JavaScript文件如果使用了相同的全局变量,或者定义了相同名字的顶层函数,都会造成命名冲突,并且很难被发现。

减少冲突的一个方法是把自己的所有变量和函数全部绑定到一个全局变量中。

  //唯一的全局变量MYAPP:
var MYAPP = {};
//其他变量:
MYAPP.name = 'myapp';
MYAPP.version = 1.0;
//其他函数
MYAPP.foo = function () {
return 'foo';
};

把自己的代码全部放入唯一的命名空间MYAPP中,会大大减少全局变量冲突的可能。

局部作用域

由于JavaScript的变量作用域实际上是函数内部,我们在for循环等语句块中无法定义具有局部作用域的变量:

  'use strict':
function foo() {
for( var i = 0 ; i < 100; i++){
//
}
i +=100;//仍然可以引用变量i
}

为了解决块级作用域,ES6引入了新的关键字let,用let替代var可以申明一个块级作用域的变量:

  'use strict':
function foo() {
var sum = 0 ;
for (let i = 0 ; i < 100 ; i++){
sum +=i;
}
i += 1;//SyntaxError
}

常量:

由于var和let申明的是变量,在ES6之前是不行的,我们通常用全部大写的变量来表示“这是一个常量,不要修改它的值”:

var PI = 3.14;

ES6标准引入了新的关键字const来定义常量,const与let都具有块级作用域:

  'use strict':
const PI = 3.14;
PI = 3;//某些浏览器不报错,但是无效果!
PI;//3.14

JavaScript函数变量作用域的更多相关文章

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

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

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

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

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

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

  4. 函数变量作用域(python)

    收集参数:该参数个数不确定 >>> def test(*params): print('参数的长度是:', len(params)); print('第二个参数是:', params ...

  5. Javascript之变量作用域

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

  6. javascript的变量作用域--对比js、php和c的for循环

    为什么要写这篇文章呢?主要是给自己提个醒,js的水很深,需要小心点儿才能趟过去,更何况自己不是专业人士,那就得更加小心了. 看下面的js代码: <!DOCTYPE html> <ht ...

  7. [译]JavaScript:函数的作用域链

    原文:http://blogs.msdn.com/b/jscript/archive/2007/07/26/scope-chain-of-jscript-functions.aspx 在JavaScr ...

  8. javascript 函数和作用域(函数,this)(六)

    重点. 一.函数 1.函数介绍 函数是一块JavaScript代码,被定义一次,但可执行和调用多次.JS中的函数也是对象,所以JS函数可以像其他对象那样操作和传递,所以我们也常叫JS中的函数为函数对象 ...

  9. javascript 函数和作用域(闭包、作用域)(七)

    一.闭包 JavaScript中允许嵌套函数,允许函数用作数据(可以把函数赋值给变量,存储在对象属性中,存储在数组元素中),并且使用词法作用域,这些因素相互交互,创造了惊人的,强大的闭包效果.[upd ...

随机推荐

  1. ubuntu中mysql5.7表名区分大小写解决方案

    在/etc/mysql/mysql.conf.d/mysqld.cnf 添加lower_case_table_names=1

  2. 【Linux】快速清空当前文件

    $ : > filename $ > filename $ echo "" > filename $ echo > filename $ cat /dev/ ...

  3. vue路由配置

    1.安装 npm install vue-router --save / cnpm install vue-router --save 2.引入并 Vue.use(VueRouter) (main.j ...

  4. jstl标注标签库

    1.  常用标签 引入标签库: <%@ taglib prefix=”c” uri=”” %> 1.      C 标签   (1)<c:out value=”” default=” ...

  5. 使用Spring的AOP实现切面日志

    AOP切面日志的使用方式 @Aspect @Component public class HttpAspect { private static final Logger logger = Logge ...

  6. [SQL SERVER系列]工作经常使用的SQL整理,实战篇(二)[原创]

    工作经常使用的SQL整理,实战篇,地址一览: 工作经常使用的SQL整理,实战篇(一) 工作经常使用的SQL整理,实战篇(二) 工作经常使用的SQL整理,实战篇(三) 接着上一篇“工作经常使用的SQL整 ...

  7. scp命令的使用

    scp命令是什么 scp是 secure copy的缩写, scp是linux系统下基于ssh登陆进行安全的远程文件拷贝命令. scp命令用法 scp [-1246BCpqrv] [-c cipher ...

  8. props的异步加载问题

    在写vue项目的时候,父组件调用ajax的接口获得数据,然后赋值给data中的初始值,然后通过props传给子组件,子组件在created的时候,获得的props的值有的时候是undefined,因为 ...

  9. Latest SoC

    From: http://laoyaoba.com/ss6/html/68/n-505768.html 2014年国产ARM SoC芯片巡礼(上) 关注“集微网”,微信点播新闻.随要随有 来源: &l ...

  10. Python数组使用

    python数组的使用 2010-07-28 17:17 1.Python的数组分三种类型: (1) list 普通的链表,初始化后可以通过特定方法动态增加元素. 定义方式:arr = [元素] (2 ...