作用域与变量提升

一、作用域
1.函数作用域:变量在声明它们的函数体以及在嵌套这个函数体内都是有定义的。
先看一段代码

var scope="global"; 
function t(){ 
console.log(scope); //undefined
var scope="local" 
console.log(scope); //local
} 
t(); 

 

这里涉及到了变量提升,变量初始化后,js会将变量的声明提升到函数顶部,如果是函数外部的全局变量,则提升到js顶部(作用域顶部)
所以这段代码可以转化成
demo

var scope="global"; 
function t(){ 
var scope
console.log(scope); //undefined
scope="local" 
console.log(scope); //local
} 
t(); 
``

// 又比如,定义三个变量
demo3
``
(function(){ 
var a='One'; 
var b='Two'; 
var c='Three'; 
})() ;
``
// 实际上它变量提升后是这样的:
``
(function(){ 
var a,b,c; 
a='One'; 
b='Two'; 
c='Three'; 
})() 

 

``
##需要注意一点的是,函数有两种声明形式,一种是函数声明式,一种是函数表达式式,只有函数声明式中,变量才会被提升。

2.JS没有块级作用域
为什么这么说呢?我们可以看以下代码
demo1
``

var name="global"; 
if(true){ 
var name="local"; 
console.log(name) //local
} 
console.log(name); //local

 


``
如果说函数有块级作用域的话,那么if判断语句中的代码块应该是有自己的作用域的。但是这里的两个name打印的都是local,这是为什么呢?
第一个name是属于函数内部变量,所以固然打印的是local;
第二个name打印的其实也是local,因为var name="local"已经将函数语句外部的var name="global"覆盖。


二、变量作用域
1.js中未用var声明的变量,属于隐式全局变量,也是顶层对象的属性
我们看一个实例
demo
``

function t(flag){ 
if(flag){ 
s="ifscope"; 
for(var i=0;i<2;i++) 
; 
} 
console.log(i); 
} 
t(true); 
console.log(s); 

 


``
这段代码,外部的console.log也可以访问函数内部的s,就是因为s没有用var声明,属于全局变量,函数外部也可以访问到,所以console.log(s)的效果相当于console.log(window.s)。

2.当使用var声明一个变量时,变量无法使用delete运算符删除
var name=1 ->不可删除
sex=”girl“ ->可删除
this.age=22 ->可删除


三、作用域链
1.demo:
``

name="shark"; 
function t(){ 
var name="jan"; 
function s(){ 
var name="jack"; 
console.log(name); 
} 
function ss(){ 
console.log(name); 
} 
s(); //jack
ss(); //jan
} 
t(); 

 


``
调用对象时,js会把对象放在作用域链开头,然后将函数的调用放在之后,最后是全局对象,知道找到name为止。
上面的例子中,
s(),很明显指定是打印s()函数中的name,结果是jack,
ss(),ss内部没有name属性,那么它会到它的上一层函数中去寻找,找到name="jan",则会打印出来jan。


2.下面看一个很容易犯错的例子:
demo
``

<html> 
<head> 
<script type="text/javascript"> 
function buttonInit(){ 
for(var i=1;i<4;i++){ 
var b=document.getElementById("button"+i); 
b.addEventListener("click",function(){ alert("Button"+i);},false); 
} 
} 
window.onload=buttonInit; 
</script> 
</head> 
<body> 
<button id="button1">Button1</button> 
<button id="button2">Button2</button> 
<button id="button3">Button3</button> 
</body> 
</html> 

 


``

看了上面的代码,我们很容易会想到,结果分别打印出Button1,Button2,Button3。但是事实呢?
##注意这里点击事件里的匿名函数并没有i这个变量,所以它会到上一层函数buttonInit中去找,而注册事件结束后,i的值已经是4了,所以这里匿名函数其实是
function(){ alert("Button"+4);
所以三个按钮打印的都是Button4。

 

posted @ 2017-08-29 02:02  鲨鱼余烁  阅读(149)  评论(0编辑  收藏  举报