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 中国省市两级联动选择附图
May 14 Javascript
浅析jquery unbind()方法移除元素绑定的事件
May 24 Javascript
浅谈js多维数组和hash数组定义和使用
Jul 27 Javascript
AngularJS Bootstrap详细介绍及实例代码
Jul 28 Javascript
Bootstrap Navbar Component实现响应式导航
Oct 08 Javascript
etmvc+jQuery EasyUI+combobox多值操作实现角色授权实例
Nov 09 Javascript
详解Vue组件之间的数据通信实例
Jun 17 Javascript
js实现鼠标跟随运动效果
Aug 02 Javascript
vue刷新和tab切换实例
Feb 11 Javascript
vue配置接口域名方法总结
May 12 Javascript
layui table 表格模板按钮的实例代码
Sep 21 Javascript
Vue实现简单的跑马灯
May 25 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
PHPExcel读取Excel文件的实现代码
2011/12/06 PHP
PHP autoload与spl_autoload自动加载机制的深入理解
2013/06/05 PHP
php获取当前月与上个月月初及月末时间戳的方法
2016/12/05 PHP
thinkPHP框架RBAC实现原理分析
2019/02/01 PHP
Javascript实例教程(19) 使用HoTMetal(5)
2006/12/23 Javascript
杨氏矩阵查找的JS代码
2013/03/21 Javascript
jquery改变tr背景色的示例代码
2013/12/28 Javascript
jquery.mobile 共同布局遇到的问题小结
2015/02/10 Javascript
js简单实现竖向tab选项卡的方法
2015/05/04 Javascript
Jquery数字上下滚动动态切换插件
2015/08/08 Javascript
js如何实现淡入淡出效果
2020/11/18 Javascript
AngularJS动态绑定HTML的方法分析
2016/11/07 Javascript
Angualrjs和bootstrap相结合实现数据表格table
2017/03/30 Javascript
VueJs 搭建Axios接口请求工具
2017/11/20 Javascript
解决vue-cli3 使用子目录部署问题
2018/07/19 Javascript
vue实现抖音时间转盘
2019/09/08 Javascript
VUE实时监听元素距离顶部高度的操作
2020/07/29 Javascript
探究一道价值25k的蚂蚁金服异步串行面试题
2020/08/21 Javascript
Python实现同时兼容老版和新版Socket协议的一个简单WebSocket服务器
2014/06/04 Python
Python操作MySQL数据库的三种方法总结
2018/01/30 Python
Python之文字转图片方法
2018/05/10 Python
python 读写文件,按行修改文件的方法
2018/07/12 Python
python文本数据处理学习笔记详解
2019/06/17 Python
python-序列解包(对可迭代元素的快速取值方法)
2019/08/24 Python
Python在OpenCV里实现极坐标变换功能
2019/09/02 Python
Pycharm制作搞怪弹窗的实现代码
2021/02/19 Python
Html5页面中的返回实现的方法
2018/02/26 HTML / CSS
统计每一学生的平均成绩
2014/06/06 面试题
区三好学生主要事迹
2014/01/30 职场文书
网络文明传播志愿者活动方案
2014/08/20 职场文书
部队反四风对照检查材料
2014/09/26 职场文书
2014年除四害工作总结
2014/12/06 职场文书
2015年幼儿教师个人工作总结
2015/05/20 职场文书
婚礼领导致辞大全
2015/07/28 职场文书
高中数学课堂教学反思
2016/02/18 职场文书
Python实现双向链表
2022/05/25 Python