JavaScript变量的作用域全解析


Posted in Javascript onAugust 14, 2015

变量作用域是程序中定义这个变量的区域。
先来看一段示例:

/*  代码1  */

var scope = "global ";
function checkScope() {
 var scope = "local ";
 function childCheck() {
  var scope = "childLocal ";
  document.write(scope);
 }
 function childUndefined() {
  document.write(scope);
  var scope;
 }
 function childOverride() {
  scope = "childOverride ";
  document.write(scope);
 }
 document.write(scope); //输出"local"
 childCheck();   //输出"childLocal"
 childUndefined();  //输出"undefined"
 childOverride();  //输出"childOverride"
 document.write(scope); //输出"childOverride"
}
checkScope();    //输出"local childLocal undefinedchildOverride childOverride"
document.write(scope);  //输出"global "

全局作用域与局部作用域
全局(global)变量的作用域是全局的,在Javascript中处处有定义;而函数内部声明的变量是局部(local)变量,其作用域是局部性的,只在函数体内部有定义。对于下面的输出读者应不会感到意外。
/*  代码2  */

var scope = "global";
function checkScope() {
 var scope = "local";
 document.write(scope);
}
checkScope();   //输出"local"
document.write(scope); //输出"global"

全局变量作用域中使用变量可以不用var语句,但在声明局部变量是一定要使用var语句,否则会视为对全局变量的引用。看下面代码:
/*  代码3  */

var scope = "global";
function checkScope() {
 scope = "local";
 document.write(scope);
}
checkScope();   //输出"local"
document.write(scope); //输出"local"

没有块作用域
Javascript没有块级作用域,函数中声明的变量在整个函数中都是有定义的。对于下面的代码对于生疏的读者可能颇感意外:
/*  代码4  */

var scope = "global";
function checkScope() {
 document.write(scope); //语句4.1
 var scope = "local"; //语句4.2
 document.write(scope);
}
checkScope();   //输出"undefinedlocal"

由于语句4.1(var scope = "local";)声明的变量在整个checkScope函数作用域内都有效,因此在语句4.2(document.write(scope); )执行的时scope引用的是局部变量,而此时局部变量scope尚未定义,所以输出”undefined”。因此一个好的编程习惯是将所有的变量声明集中起来放在函数的开头。

在了解了上述内容之后,读者再看看代码1应该不会感到困惑了。
对象的属性变量
对象的属性变量比较容易理解,看一下下面的代码读者应该不会感到疑惑。
/*  代码5  */

var scope = "global ";
var obj = new Object();
obj.scope = "object ";
obj.checkScope = function () {
 var scope = "loacl ";
 document.write(scope);   //输出"loacl"
 document.write(this.scope);  //输出"object"
 document.write(window.scope); //输出"global"
}
obj.checkScope(); //输出"loacl object global"

所谓作用域,就是说这个变量在代码块中的有效范围。如果不理解 JavaScript 作用域,调试代码的时候可能会比较困难。

在函数中,如果用var来声明一个变量,那么该变量的作用域就只限于该函数内部,函数外的代码无法访问该变量。如果在该函数中再声明一个函数,那么这个内部的函数也可以访问这个变量。

反过来,如果声明变量的时候没有用var,那么此变量的作用域就不局限于这个函数了。JavaScript 引擎会再全局范围中检查该变量是否被定义过。如果该变量没有被定义过,那么它就会被定义为一个全局变量。

函数可以访问相同作用域中的变量:

var foo = 'hello';

var sayHello = function() {
 console.log(foo);
};

sayHello();   // logs 'hello'
console.log(foo); // also logs 'hello'

变量作用域之外的代码不能访问该变量:

var sayHello = function() {
 var foo = 'hello';
 console.log(foo);
};

sayHello();   // logs 'hello'
console.log(foo); // doesn't log anything

不用作用域中名称相同的变量,有不同的值:

var foo = 'world';

var sayHello = function() {
 var foo = 'hello';
 console.log(foo);
};

sayHello();   // logs 'hello'
console.log(foo); // logs 'world'

函数定以后可以看到函数内变量值的改变:

var myFunction = function() {
 var foo = 'hello';

 var myFn = function() {
  console.log(foo);
 };

 foo = 'world';

 return myFn;
};

var f = myFunction();
f(); // logs 'world' -- haha

作用域也会穿越 — 闭包

// 一个自执行的匿名函数
(function() {
 var baz = 1;
 var bim = function() { alert(baz); };
 bar = function() { alert(baz); };
})();

console.log(baz); // 在函数外面不能访问 baz

bar(); // 声明 bar 的时候并没有用 var
  // 所以 bar 是一个全局变量; 但是,
  // bar 和 baz 在相同的作用域内被定义,
  // 所以 bar 可以访问 baz
  // 其实 bar 是个闭包函数

bim(); // bim 的作用域只限于匿名函数内部,
  // 所以这里不能调用

综合

所谓作用域,就是说这个变量在代码块中的有效范围。如果不理解 JavaScript 作用域,调试代码的时候可能会比较困难。

在函数中,如果用var来声明一个变量,那么该变量的作用域就只限于该函数内部,函数外的代码无法访问该变量。如果在该函数中再声明一个函数,那么这个内部的函数也可以访问这个变量。

反过来,如果声明变量的时候没有用var,那么此变量的作用域就不局限于这个函数了。JavaScript 引擎会再全局范围中检查该变量是否被定义过。如果该变量没有被定义过,那么它就会被定义为一个全局变量。

函数可以访问相同作用域中的变量:

var foo = 'hello';

var sayHello = function() {
 console.log(foo);
};

sayHello();   // logs 'hello'
console.log(foo); // also logs 'hello'

变量作用域之外的代码不能访问该变量:

var sayHello = function() {
 var foo = 'hello';
 console.log(foo);
};

sayHello();   // logs 'hello'
console.log(foo); // doesn't log anything

不用作用域中名称相同的变量,有不同的值:

var foo = 'world';

var sayHello = function() {
 var foo = 'hello';
 console.log(foo);
};

sayHello();   // logs 'hello'
console.log(foo); // logs 'world'

函数定以后可以看到函数内变量值的改变:

 
var myFunction = function() {
 var foo = 'hello';

 var myFn = function() {
  console.log(foo);
 };

 foo = 'world';

 return myFn;
};

var f = myFunction();
f(); // logs 'world' -- haha

作用域也会穿越 — 闭包

// 一个自执行的匿名函数
(function() {
 var baz = 1;
 var bim = function() { alert(baz); };
 bar = function() { alert(baz); };
})();

console.log(baz); // 在函数外面不能访问 baz

bar(); // 声明 bar 的时候并没有用 var
  // 所以 bar 是一个全局变量; 但是,
  // bar 和 baz 在相同的作用域内被定义,
  // 所以 bar 可以访问 baz
  // 其实 bar 是个闭包函数

bim(); // bim 的作用域只限于匿名函数内部,
  // 所以这里不能调用
Javascript 相关文章推荐
jQuery的实现原理的模拟代码 -3 事件处理
Aug 03 Javascript
uploadify在Firefox下丢失session问题的解决方法
Aug 07 Javascript
jquery禁止回车触发表单提交
Dec 12 Javascript
创建你的第一个AngularJS应用的方法
Jun 16 Javascript
从零开始学习Node.js系列教程之SQLite3和MongoDB用法分析
Apr 13 Javascript
jQuery动态添加.active 实现导航效果代码思路详解
Aug 29 jQuery
使用clipboard.js实现复制功能的示例代码
Oct 16 Javascript
浅谈vux之x-input使用以及源码解读
Nov 04 Javascript
详解关于Vuex的action传入多个参数的问题
Feb 22 Javascript
如何通过shell脚本自动生成vue文件详解
Sep 10 Javascript
JS检索下拉列表框中被选项目的索引号(selectedIndex)
Dec 17 Javascript
基于JavaScript实现表格隔行换色
May 08 Javascript
DEDECMS如何为文章添加HOT NEW标志图片
Aug 14 #Javascript
JavaScript实现给按钮加上双重动作的方法
Aug 14 #Javascript
详解jQuery中的元素的属性和相关操作
Aug 14 #Javascript
js实现人才网站职位选择功能的方法
Aug 14 #Javascript
jQuery入门基础知识学习指南
Aug 14 #Javascript
Jquery全选与反选点击执行一次的解决方案
Aug 14 #Javascript
js实现Select列表各项上移和下移的方法
Aug 14 #Javascript
You might like
虫族 Zerg 魔法科技
2020/03/14 星际争霸
xml+php动态载入与分页
2006/10/09 PHP
PHP在线生成二维码代码(google api)
2013/06/03 PHP
浅析PHP数据导出知识点
2018/02/17 PHP
基于Jquery的标签智能验证实现代码
2010/12/27 Javascript
JavaScript高级程序设计 事件学习笔记
2011/09/10 Javascript
jquery $.each 和for怎么跳出循环终止本次循环
2013/09/27 Javascript
AngularJS的内置过滤器详解
2015/05/14 Javascript
jquery实现图片上传之前预览的方法
2015/07/11 Javascript
JavaScript中var关键字的使用详解
2015/08/14 Javascript
几种经典排序算法的JS实现方法
2016/03/25 Javascript
JS版微信6.0分享接口用法分析
2016/10/13 Javascript
AngularJS 获取ng-repeat动态生成的ng-model值实例详解
2016/11/29 Javascript
Bootstrap popover 实现鼠标移入移除显示隐藏功能方法
2018/01/24 Javascript
基于mpvue搭建微信小程序项目框架的教程详解
2019/04/10 Javascript
10种检测Python程序运行时间、CPU和内存占用的方法
2015/04/01 Python
Python操作MySQL数据库的方法
2018/06/20 Python
python实现自动网页截图并裁剪图片
2018/07/30 Python
python用pandas数据加载、存储与文件格式的实例
2018/12/07 Python
Python中GeoJson和bokeh-1的使用讲解
2019/01/03 Python
Django框架视图介绍与使用详解
2019/07/18 Python
python使用flask与js进行前后台交互的例子
2019/07/19 Python
使用Python实现Wake On Lan远程开机功能
2020/01/22 Python
关于多元线性回归分析——Python&SPSS
2020/02/24 Python
Python轻量级web框架bottle使用方法解析
2020/06/13 Python
openCV提取图像中的矩形区域
2020/07/21 Python
Html5之webcoekt播放JPEG图片流
2020/09/22 HTML / CSS
如何在Oracle中查看各个表、表空间占用空间的大小
2015/10/31 面试题
95%的面试官都会问到的50道Java线程题,附答案
2012/08/03 面试题
Unix控制后台进程都有哪些进程
2016/09/22 面试题
大学生预备党员自我评价分享
2013/11/16 职场文书
丑小鸭教学反思
2014/02/03 职场文书
大学生全国两会报告感想
2014/03/17 职场文书
设备售后服务承诺书
2014/05/30 职场文书
公司管理制度范本
2015/08/03 职场文书
golang使用map实现去除重复数组
2022/04/14 Golang