作用域
作用域的含义
- 作用域就是变量和函数的可访问范围
- 影响变量和函数的可见性与生命周期
- JavaScript包括全局作用域和局部作用域
- JavaScript没有块级作用域(用闭包解决)
- JavaScript会预编译变量和函数
- 作用域就是变量和函数的可访问范围
//全局作用域 var a="123"; function test(){ console.log("test内调用外部变量a:"+a); //可以作用到任何地方 } test();
结果: test内调用外部变量a:123
- 影响变量和函数的可见性与生命周期
//函数作用域 function test(){ function inner(){ console.log("inner"); } inner(); } test(); inner();
结果:
inner
inner is not defined
- JavaScript包括全局作用域和局部作用域
//函数内变量作用域
function test(){
var b="123";
console.log("test内部变量b:"+b);
}
test();
console.log("外部调用变量b:"+b);
结果:
test内部变量b:123
外部调用变量b:undefined
//函数内变量作用域2
function test(){
b="123";
console.log("test内部变量b:"+b);
}
test();
console.log("外部调用变量b:"+b);
结果:
test内部变量b:123
外部调用变量b:123
- JavaScript没有块级作用域(块级:for,if,switch,【用闭包解决】)
//块级作用域,JS没有块级作用域 for(var b=1;b<5;b++){ } console.log(b);
结果:
5 //这个5是i最终的结果来直接打印出来的,并不是i循环得出来的
要想解决这个问题,只有使用闭包,下面会讲闭包
- JavaScript会预编译变量和函数
//预编译变量和函数 var c="123"; function test(){ //console.log(d); console.log(c); var c="456"; console.log(c); } test();
结果:
underfined //第一个c
456 //第二个c
上面的代码 被 编译器 编译成 :
//预编译变量和函数 var c="123"; function test(){ //console.log(d); var c; console.log(c); var c="456"; console.log(c); } test();
解析:本来第一个c是可以打印出来 123 的 ,但是 下面又出现了第二个c(函数内重新定义相同变量会,作用域会改变),所以第一个c打印出underfined。
//预编译变量和函数
var c="123";
function test(){
console.log(d);
console.log(c);
var c="456";
console.log(c);
}
test();
结果: d is not defined
小结:underfined与is not defined 是两个完全不同的概念。
underfined是定义过的,但未赋值。
is not defined是未定义也未赋值。
执行上下文( execution context)
要点
- 全局执行上下文为window对象
- 每个函数都有自己的执行上下文
- 全局的执行上下文在当前窗口关闭后被销毁
- 执行上下文有一个与之相对应的变量对象
过程
- 单线程
- 函数的执行上下文的个数没有限制
- 每次某个函数被调用,就会有个新的执行上下文为其创建
- 即使是调用的自身函数,也会创建新的执行上下文
执行上下文( execution context)代码执行阶段
- 变量赋值
- 函数引用
- 执行其它代码
- Variable Object变量对象 Active Object活动对象
如下代码
function foo(i) { var a = 'hello'; var b = function privateB() { }; function c() { } } foo(22);
//建立阶段(解析)
fooExecutionContext = { variableObject: { arguments: { 0: 22, //第一个参数 length: 1 //第一个参数的长度 }, i: 22, //第一个参数传进来的是22 c: pointer to function c() //初始化函数 a: undefined,//声明 b: undefined//声明 }, scopeChain: { ... }, this: { ... } }
//代码执行阶段
//代码执行阶段
fooExecutionContext = {
variableObject: {
arguments: {
0: 22,//第一个参数
length: 1 //第一个参数的长度
},
i: 22,//第一个参数传进来的是22
c: pointer to function c()//初始化函数
a: 'hello', //赋值
b: pointer to function privateB()//给函数赋值
},
scopeChain: { ... },
this: { ... }
}
闭包
含义
- 闭包是指有权限访问另一个函数作用域的变量的函数
- 创建闭包的常见方式就是在一个函数内部创建另一个函数
作用:
不销毁 函数内部的变量
如下代码
HTML
<span>1</span> <span>2</span> <span>3</span>
javascript
var elements=document.getElementsByTagName("span"); for(var i=0;i<elements.length;i++){ elements[i].onclick=function(){ console.log(i); } }
结果:3//i是直接输出3,并不是循环得出的结果,要想解决这个问题就要用到 闭包,如下
for(var i=0;i<elements.length;i++){ (function (m){ elements[i].onclick=function(){ console.log(m); } })(i);//将i当作function对象传进来 }结果:0 1 2
闭包实例1:(作用:不销毁 函数内部的变量)