深入理解jsavascript的作用域
一、 JavaScript声明提前
在JavaScript中如果不创建变量,直接去使用,则报错:
console.log(xxoo);
// 报错:Uncaught ReferenceError: xxoo is not defined
JavaScript中如果创建值而不赋值,则该值为 undefined,如:
var xxoo;
console.log(xxoo);
// 输出:undefined
在函数内如果这么写:
function Foo(){
console.log(xo);
var xo = 'seven';
}
Foo();
// 输出:undefined
上述代码,不报错而是输出 undefined,其原因是:JavaScript的函数在被执行之前,会将其中的变量全部声明,而不赋值。所以,相当于上述实例中,函数在“预编译”时,已经执行了var xo;所以上述代码中输出的是undefined。
二、JavaScript以函数为作用域
1、在JavaScript中每个函数作为一个作用域,在外部无法访问内部作用域中的变量。
function Main(){
var innerValue = 'seven';
}
Main();
console.log(innerValue);
// 报错:Uncaught ReferenceError: innerValue is not defined
三、JavaScript函数的作用域栈
由于JavaScript中的每个函数作为一个作用域,如果出现函数嵌套函数,则就会出现作用域栈(先进后出)。
a = '全局';
function Outer(){
var a = "o";
function inner(){
var a = 'i';
console.log(a);
}
inner();
}
Outer();
如上述代码则出现三个作用域组成的作用域栈,如果出现作用域栈后,那么寻找变量时候就会出现顺序,对于上述实例:
代码从上到下执行的时候,以从外到内的顺序将每个变量入栈。全局变量在栈底部。
当执行console.log(xo)时,其寻找顺序为根据作用栈从内到外的优先级寻找,如果内层没有就逐步向外层查找,直到没找到抛出异常。
JavaScript的函数在被执行之前,会将其中的变量全部声明,并在作用域栈中占据相应的坑位。


四、JavaScript的作用域栈执行前已创建
JavaScript的作用域在被执行之前已经创建,日后再去执行时只需要按照作用域栈去寻找即可。参考二的图一,在函数被执行前作用域已经形成了,只是函数变量未被赋值。
示例一:
a= '全局';
function Outer(){
var a= "O";
function inner(){
console.log(a);
}
return inner;
}
var ret = Func();
ret();
// 输出结果: O
上述代码,在函数被调用之前作用域链已经存在。

由于函数创建时,作用域已经创建,因此最后的作用域结果入上图。ret=inner。因此执行inner()函数,当然首先查找到本层函数的变量a='O' 。
示例二:
a= '全局';
function Outer(){
var a= "O";
function inner(){
console.log(a);
}
a = 'B';
return inner;
}
var ret = Func();
ret();
// 输出结果: B
上述代码和示例一的目的相同,也是强调在函数被调用之前作用域链已经存在。

inner函数中在函数执行钱a变量游“O"被重置为”B",因此最后执行结果为B。
示例三:
a= '全局';
function Bar(){
console.log(a);
}
function Outer(){
var a= "O";
return Bar;
}
var ret = Func();
ret();
// 输出结果: '全局'
上述代码,在函数被执行之前已经创建了两条作用域链(同级函数会创建个平行作用域,共享他们的父级函数的的变量):

当执行et();时,ret代指的Bar函数,而Bar函数的作用域链已经存在:全局作用域 -> Bar函数作用域,所以,执行时会根据已经存在的作用域链去寻找。
其他例子 :
function func() {
for(i=0;i<3;i++){
setInterval(function () {
console.log(i)
},1000)
}
}
//每秒输出3个3
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
</head>
<body>
<input type="button" value="按钮1">
<input type="button" value="按钮2">
<input type="button" value="按钮3"> <script>
inps = document.getElementsByTagName("input")
for(i=0;i<3;i++){
cur_inp = inps[i];
cur_inp.onclick = function () {
alert(3)
}
}
//所有的按钮点击都是输出3
</script>
</body>
</html>
深入理解jsavascript的作用域的更多相关文章
- 个人理解的javascript作用域链与闭包
闭包引入的前提个人理解是为从外部读取局部变量,正常情况下,这是办不到的.简单的闭包举例如下: function f1(){ n=100; function f2(){ alert(n); } retu ...
- 理解AngularJS的作用域Scope
AngularJS中,子作用域一般都会通过JavaScript原型继承机制继承其父作用域的属性和方法.但有一个例外:在directive中使用scope: { ... },这种方式创建的作用域是一个独 ...
- JavaScript闭包理解的关键 - 作用域链
阮一峰的一篇文章已经对闭包的用途.概念讲解地相对清晰了. 闭包就是能够读取其他函数内部变量的函数. 但我认为里面对于作用域链的解释还不够清晰,这里作一些补充. 闭包之所以可以读取外部函数的内部变量,即 ...
- 通过作用域链解析js函数一些难以理解的的作用域问题
基本原理 js函数在执行时,系统会创建一个隐式的属性scope,scope中存储的是函数的作用域链. 通过对这个scope的分析,就能解释JavaScript中许多难以理解的问题: 例1: funct ...
- 通过a++来理解闭包改变作用域的问题
纯属个人理解,如果有误请指出! 让我们先看一段代码 function dog(){ var a=100; a++; return a; } alert(dog()); alert(dog()); 我们 ...
- 理解JavaScript的作用域链
上一篇文章中介绍了Execution Context中的三个重要部分:VO/AO,scope chain和this,并详细的介绍了VO/AO在JavaScript代码执行中的表现. 本文就看看Exec ...
- 理解angularjs的作用域
<!doctype html> <html ng-app="myApp"> <head> <script src="http:/ ...
- 深入理解Javascript变量作用域
在学习JavaScript的变量作用域之前,我们应当明确几点: a.JavaScript的变量作用域是基于其特有的作用域链的. b.JavaScript没有块级作用域. c.函数中声明的变量在整个函数 ...
- 理解angularJS中作用域$scope
angularJS中作用域是什么 作用域(scope)是构成angularJS应用的核心基础,在整个框架中都被广泛使用,因此了解它如何工作是非常重要的 应用的作用域是和应用的数据模型相关联的,同时作用 ...
随机推荐
- 数据结构笔记02:Java面试必问算法题
1. 面试的时候,栈和队列经常会成对出现来考察.本文包含栈和队列的如下考试内容: (1)栈的创建 (2)队列的创建 (3)两个栈实现一个队列 (4)两个队列实现一个栈 (5)设计含最小函数min()的 ...
- IJKMediaFramework第三方库的使用
大多数做直播的时候使用 FFMpeg. IJKMediaFramework也是基于FFMpeg封装 使用起来比较简单,个人觉得如果有能力可以使用 FFMpeg , 使用 FFMpeg对 内存的占用比 ...
- PL/SQL developer 使用技巧汇总
为了快速的使用PL/SQL developer 进行 oracle数据库相关开发,将一些使用频率较高的使用技巧进行汇总如下,以下转自网络和自己的测试 1.切换schema --switch schem ...
- [改善Java代码]推荐在复杂字符串操作中使用正则表达式
一.分析 字符串的操作,诸如追加.合并.替换.倒序.分隔等,都是在编码过程中经常用到的,而且Java也提供了append.replace.reverse.split等方法来完成这些操作,它们使用起来 ...
- [改善Java代码]使用构造块精炼程序
建议36: 使用构造代码块精炼程序 什么叫代码块(Code Block)?用大括号把多行代码封装在一起,形成一个独立的数据体,实现特定算法的代码集合即为代码块,一般来说代码块是不能单独运行的,必须要有 ...
- hdu 4612 边连通度缩点+树的最长路径
思路:将以桥为分界的所有连通分支进行缩点,得到一颗树,求出树的直径.再用树上的点减去直径,再减一 #pragma comment(linker, "/STACK:1024000000,102 ...
- java算法小知识练习(二)
话不多说,直接上题: 题目:两个乒乓球队进行比赛,各出三人.甲队为a,b,c三人,乙队为x,y,z三人.已抽签决定比赛名单. 有人向队员打听比赛的名单.a说他不和x比,c说他不和x,z比,请编程序 ...
- js如何判断一个数组中是否有重复的值
引自:http://bbs.tianya.cn/post-414-38497-1.shtml 方法一: var ary = new Array("111","22&quo ...
- 第九章 jQuery验证插件简介
1. 表单验证插件-----Validation <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" ...
- 备忘====[HttpPost]和[AcceptVerbs(HttpVerbs.Post)]区别
1.共同点:[HttpPost]和[AcceptVerbs(HttpVerbs.Post)]都是只接受POST请求过来的数据. 2.不同点:在MVC中如果想一个action既可以回应POST请求也可以 ...