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 相关文章推荐
javascript 简练的几个函数
Aug 29 Javascript
JS文本框默认值处理详解
Jul 10 Javascript
Javascript delete 引用类型对象
Nov 01 Javascript
用js+iframe形成页面的一种遮罩效果的具体实现
Dec 31 Javascript
jQuery插件开发的五种形态小结
Mar 04 Javascript
JQuery的attr 与 val区别
Jun 12 Javascript
jQuery回到顶部的代码
Jul 09 Javascript
Angular2的管道Pipe的使用方法
Nov 07 Javascript
JS实现的简单拖拽购物车功能示例【附源码下载】
Jan 03 Javascript
小程序Scroll-view上拉滚动刷新数据
Jun 21 Javascript
jQuery实现滑动开关效果
Aug 02 jQuery
在vue-cli创建的项目中使用sass操作
Aug 10 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
用PHP实现小型站点广告管理
2006/10/09 PHP
javascript 页面只自动刷新一次
2009/07/10 Javascript
web前端设计师们常用的jQuery特效插件汇总
2014/12/07 Javascript
使用Bootstrap Tabs选项卡Ajax加载数据实现
2016/12/23 Javascript
微信小程序 devtool隐藏的秘密
2017/01/21 Javascript
layui radio性别单选框赋值方法
2018/08/15 Javascript
vue 监听屏幕高度的实例
2018/09/05 Javascript
vue项目引入字体.ttf的方法
2018/09/28 Javascript
layui的表单提交以及验证和修改弹框的实例
2019/09/09 Javascript
VUE中鼠标滚轮使div左右滚动的方法详解
2020/12/14 Vue.js
python和shell实现的校验IP地址合法性脚本分享
2014/10/23 Python
Python入门_浅谈数据结构的4种基本类型
2017/05/16 Python
使用python读取txt文件的内容,并删除重复的行数方法
2018/04/18 Python
Face++ API实现手势识别系统设计
2018/11/21 Python
Flask项目中实现短信验证码和邮箱验证码功能
2019/12/05 Python
简单了解Django ORM常用字段类型及参数配置
2020/01/07 Python
python GUI库图形界面开发之PyQt5布局控件QGridLayout详细使用方法与实例
2020/03/06 Python
Mac PyCharm中的.gitignore 安装设置教程
2020/04/16 Python
Python实现打包成库供别的模块调用
2020/07/13 Python
python使用建议技巧分享(三)
2020/08/18 Python
移动端rem布局的两种实现方法
2018/01/03 HTML / CSS
CSS3改变浏览器滚动条样式
2019/01/04 HTML / CSS
详解HTML5 录音的踩坑之旅
2017/12/26 HTML / CSS
介绍一下游标
2012/01/10 面试题
MVC的各个部分都有那些技术来实现?如何实现?
2016/04/21 面试题
高中地理教学反思
2014/01/29 职场文书
《天游峰的扫路人》教学反思
2014/04/25 职场文书
大专生找工作自荐书
2014/06/10 职场文书
船舶工程技术专业求职信
2014/08/07 职场文书
2015小学教师德育工作总结
2015/05/12 职场文书
医院感染管理制度
2015/08/05 职场文书
学校趣味运动会开幕词
2016/03/04 职场文书
个人道歉信大全
2019/04/11 职场文书
原生JS封装vue Tab切换效果
2021/04/28 Vue.js
python入门学习关于for else的特殊特性讲解
2021/11/20 Python
Alexa停服!网站排名将何去何从?目前还没有替代品。
2022/04/15 杂记