一,每一个变量都是有作用域的。
1,首先讲一下代码块与作用域:for, if等语句还有function,他们都有一个特点,就是后面有一对{}比如
for(var i = 0; i < items.length; i++){
//“{”和“}”之间有代码
}
if(some_express){
//“{”和“}”之间有代码
}
function(param1){
//“{”和“}”之间有代码
}
所有{}包起来的代码,都可以称之为 “代码块” , 英文名叫Block。
每个代码块都有一个自己的作用域,作用域决定了变量能否被访问(不论读取变量还是修改变量)。
访问的规则大概是这样的:
[1] 在最上层没有任何{}包裹的作用域为顶层作用域,声明的变量是哪里都可以访问的,如:
var x = 5;
if(x>0){ //可以访问
x = 6; //可以访问
}
function print_x(){
console.log(x); //也可以访问
}
[2] 任何一个代码块,{}之间的代码区域称之为它的作用域,每一对大括号括起来的代码块里声明的变量,只能在这个代码块的作用域里访问,不过在js里是不具备这个能力的。 但是为了建立起正确的思维观,我们还是要讲讲块级作用域。虽然语言不支持,但我们人不要跨越块级作用域,这是一个基本素质,会极大的减少Bug发生率。
if(true) { var x = 5; console.log(x); //可以访问 } console.log(x); //其他语言里无法访问,但是在js里可以
[3] 代码块是有层级的,在一个代码块里写的新的代码块,后者是前者的子作用域
if(true){ //相对于下面的代码块的父作用域 var x = 5; if(x > 0){ //子作用域 } }
[4] 子作用域可以访问父作用域的变量,但是父作用域无法访问子作用域的变量
if(true){ var x = 5; if(x > 0){ var y = "a"; console.log(x); //可以访问 x = 6; //也可以访问 } console.log(y); //不应该在这里再访问了。 }
[5] 作用域的父级的父级作用域的变量,该作用域里也可以访问,甚至无穷多级父的作用域里的变量都可以被访问,这种无穷多级的父,被称之为祖先
if(true){ var x = 5; if(x > 0){ console.log(x); //可以访问 for(var i = 0; i < x; i++){ console.log(x); //也可以访问 } } }
[6] 顶层作用域是所有作用域的祖先
2,函数的作用域
函数比起if,for等代码块有一个显著地不同,就是他可以在参数列表里声明变量
function a(param1, param2){ //这里就可以使用param1和param2了 }
在父作用域声明的变量,也可以在函数内被访问
var x = 5; function a(param1){ console.log(x); //可以访问到,打印的是5 }
关于作用域的覆盖问题,当子作用域有变量与父作用域重名的时候,在子作用域里只能访问到子作用域的变量。称之为 覆盖。
var x = 5;
function a(x){
console.log(x); //这时访问的x就不是父作用域的x了,而是参数x
}
a(6); //打印的是6
console.log(x); //打印的是5
所以,子作用域的覆盖不会消除父作用域的变量
var x = 5;
function a(x){
console.log(x); //这时访问的x就不是父作用域的x了,而是参数x
}
a(6); //打印的是6
console.log(x); //打印的是5
例如:
var x = 5;
function a(x){
if(x > 0){
x++;
}
console.log(x);
}
a(1);
console.log(x);
代码的最后一行输出结果是5. //因为覆盖并不会改变父作用域的变量。
3,要注意一些容易犯的错误:
for(var i = 0; i < 3; i++){
var result = [];
result.push(i);
}
console.log(result); //有的初学者以为这里会打印 [0,1,2],实际上会打印[2],因为result是在for里面被定义的, 每次循环都被重新初始化了
关于覆盖也是容易出错误:
var x = 0;
function fun(){
console.log(x);
var x = 1;
x++;
}
fun();
我们想先用一下全局变量x,然后再在子作用域里声明一个重名的局部变量x。结果我们会发现console.log()打印出的是 undefined。 因为js虽然是解释执行的,但是在一个作用域里声明的变量在这个作用域里只有一个指向,即便还没有执行到正式声明的哪一行,父级作用域的变量也已经因覆盖无法访问了 二,为了避免一些不必要的错误,我们在书写代码的时候要注意规范命名,养成好的习惯,提高写代码的效率。
相关推荐
认识函数作用域 作用域的分类 JavaScript 认识函数作用域 思考:声明变量后就可以在任意位置使用该变量嘛? 回答:不是。 举例:函数内var关键字声明的变量,不能在函数外访问。 示例 1.作用域分类 认识函数作用域 ...
javascript中没有块级作用域,取而代之的javascript使用的是函数作用域,下面使用示例学习一下js作用域的使用方法
javascript中没有块级作用域。取而代之的javascript使用的是函数作用域(function scope):变量在声明它的函数体以及这个函数体嵌套的任意函数体内都是有定义的。
// 局部变量:在函数作用域之间里的一个或者多个函数或者作用域,在局部作用域中定义的变量 局部变量。只有在该作用域内可以访问 // 局部作用域:任何一个函数的内部都有一个局部作用域,在局部作用域中定义的...
本文为大家介绍了Python函数作用域的查找顺序,供大家参考,具体内容如下 1.什么是LEGB? L:local 函数内部作用域 E:enclosing 函数内部与内嵌函数之间 G:global 全局作用域 B:build-in 内置作用域 2.LEGB是作...
计算机后端-PHP视频教程. php与mysql加强- 02. php加强28-函数作用域.wmv
千锋Web前端教程_23_函数_作用域
在ES6之前,javascript只有全局作用域和函数作用域。所谓作用域就是一个变量定义并能够被访问到的范围。也就是说如果一个变量定义在全局(window)上,那么在任何地方都能访问到这个变量,如果这个变量定义在函数...
本文实例分析了JavaScript函数作用域链。分享给大家供大家参考。具体分析如下: 作用域链: JavaScript的每个函数function都有自己的作用域,使用Active Object(简称AO)活动对象来保存,在相互嵌套的函数中形成了...
目录 JS三座大山同步异步同步异步区别作用域、闭包函数作用域链块作用域闭包闭包解决用var导致下标错误的问题投票机闭包两个面试题原型、原型链原型对象原型链完整原型链图 JS三座大山 同步异步同步异步区别...
从基础开始讲解python 包、模块、函数与变量作用域等内容
NULL 博文链接:https://xieyaxiong.iteye.com/blog/1558277
javascript使用函数作用域,即变量在声明它们的函数体以及这个函数体嵌套的任意函数体内都是有定义的,也即函数内声明的所有变量在函数体内始终是可见的。这样就意味着变量在声明之前就可以使用,这个特性被称为”...
讲到这里,首先理解两个概念:块级作用域与函数作用域。 什么是块级作用域呢? 任何一对花括号({和})中的语句集都属于一个块,在这之中定义的所有变量在代码块外都是不可见的,我们称之为块级作用域。 函数作用...
关于ES6中let 和 const 命令的用法以及注意事项:中的报错的样式ES6 引入了块级作用域,明确允许在块级作用域之中声明函数。ES6 规定,块级作用域之中,函数声明语句的行为类似于let,在块级作用域之外不可引用。
js代码-闭包原理实例 ES5 只要函数作用域,无块级作用域