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 相关文章推荐
推荐dojo学习笔记
Mar 24 Javascript
ajax与302响应代码测试
Oct 23 Javascript
JavaScript编程中实现对象封装特性的实例讲解
Jun 24 Javascript
详解MVC如何使用开源分页插件(shenniu.pager.js)
Dec 16 Javascript
JS中如何实现点击a标签返回页面顶部的问题
Jan 19 Javascript
Angular directive递归实现目录树结构代码实例
May 05 Javascript
vue.js全局API之nextTick全面解析
Jul 07 Javascript
vue使用自定义icon图标的方法
May 14 Javascript
vue 中的keep-alive实例代码
Jul 20 Javascript
JavaScript事件对象深入详解
Dec 30 Javascript
Vue表单之v-model绑定下拉列表功能
May 14 Javascript
Jquery让form表单异步提交代码实现
Nov 14 jQuery
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大批量数据操作时临时调整内存与执行时间的方法
2011/04/20 PHP
分享最受欢迎的5款PHP框架
2014/11/27 PHP
[原创]php简单防盗链验证实现方法
2016/07/09 PHP
php封装的数据库函数与用法示例【参考thinkPHP】
2016/11/08 PHP
THINKPHP在添加数据的时候获取主键id的值方法
2017/04/03 PHP
php微信公众号开发之现金红包
2018/04/16 PHP
javascript编程起步(第五课)
2007/01/10 Javascript
通过JAVASCRIPT读取ASP设定的COOKIE
2007/02/15 Javascript
通过url查找a元素应用案例
2014/04/29 Javascript
基于jQuery实现的菜单切换效果
2015/10/16 Javascript
终于实现了!精彩的jquery弹幕效果
2016/07/18 Javascript
jquery表单提交带错误信息提示效果
2017/03/09 Javascript
Vue.js实现模拟微信朋友圈开发demo
2017/04/20 Javascript
JS实现加载和读取XML文件的方法详解
2017/04/24 Javascript
Javascript实现从小到大的数组转换成二叉搜索树
2017/06/13 Javascript
详解vuex状态管理模式
2018/11/01 Javascript
js数组去重的方法总结
2019/01/18 Javascript
vue实现div可拖动位置也可改变盒子大小的原理
2020/09/16 Javascript
查看Django和flask版本的方法
2018/05/14 Python
Python装饰器的执行过程实例分析
2018/06/04 Python
用Django写天气预报查询网站
2018/10/21 Python
django重新生成数据库中的某张表方法
2019/08/28 Python
Python二维数组实现求出3*3矩阵对角线元素的和示例
2019/11/29 Python
python定时截屏实现
2020/11/02 Python
如何用python写个模板引擎
2021/01/14 Python
印尼穆斯林时尚购物网站:Hijabenka
2016/12/10 全球购物
AP澳洲中文网:澳洲正品直邮,包税收件无忧
2019/07/12 全球购物
北京天润融通.net面试题笔试题
2012/02/20 面试题
业务代表的岗位职责
2013/11/16 职场文书
活动策划邀请函
2014/02/06 职场文书
教师网络培训感言
2014/03/09 职场文书
2015年医院创卫工作总结
2015/04/22 职场文书
东京审判观后感
2015/06/01 职场文书
汽车销售合同文本
2019/08/08 职场文书
公司财务制度:成本管理控制制度模板
2019/11/19 职场文书
gateway与spring-boot-starter-web冲突问题的解决
2021/07/16 Java/Android