js变量声明提升,变量作用域与函数作用域,作用域链

JavaScript引擎在执行时,会把所有变量的声明都提升到当前作用域的最前面。

比如下边的代码:

 

var v = "hello";
(function(){
  console.log(v);
  var v = "world";
})();

这段代码的执行结果为undefined

 

这说明两个问题:

1.匿名function作用域中的v没有受到外部的影响,这说明javascript是没有块级作用域的函数是JavaScript中唯一拥有自身作用域的结构
2.function作用域内,变量v的声明被提升了,等同如下:

 

var v = "hello";
(function(){
  var v; //
  console.log(v);
  v = "world";
})();

 

 

 

声明提升

当前作用域内的声明都会提升到作用域的最前面,包括变量和函数的声明

 

(function(){
  var a = "1";
  var f = function(){};
  var b = "2";
  var c = "3";
})();

 

变量a,f,b,c的声明会被提升到函数作用域的最前面,类似如下:

 

(function(){
  var a,f,b,c;
  a = "1";
  f = function(){};
  b = "2";
  c = "3";
})();

 

请注意函数表达式并没有被提升,这也是函数表达式与函数声明的区别。进一步看二者的区别:

 

(function(){
  //var f1,function f2(){}; //被隐式提升的声明
 
  f1(); //这种写法会报错,无法调到f1函数,必须写在函数表达式之后
  f2();
 
  var f1 = function(){};
  function f2(){}
})();

 

上面代码中函数声明f2被提升,所以在前面调用f2是没问题的。虽然变量f1也被提升,但f1提升后的值为undefined,其真正的初始值是在执行到函数表达式处被赋予的。所以只有声明是被提升的。

未用var声明的变量作用域

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


s会输出为:2 ifscope

 

这主要是Js中没有用var声明的变量都是全局变量,而且是顶层对象的属性。

作用域链

 

先来看一段代码:

 

name="lwy";  
function t(){  
    var name="tlwy";  
    function s(){  
        var name="slwy";  
        console.log(name);  
    }  
    function ss(){  
        console.log(name);  
    }  
    s();  
    ss();  
}  
t(); 

 

当执行s时,将创建函数s的执行环境(调用对象),并将该对象置于链表开头,然后将函数t的调用对象链接在之后,最后是全局对象。然后从链表开头寻找变量name,很明显

name是"slwy"。

但执行ss()时,作用域链是: ss()->t()->window,所以name是”tlwy"

下面看一个很容易犯错的例子:

 

<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>  

 

当文档加载完毕,给几个按钮注册点击事件,当我们点击按钮时,会弹出什么提示框呢?

很容易犯错,对是的,三个按钮都是弹出:"Button4",你答对了吗?

当注册事件结束后,i的值为4,当点击按钮时,事件函数即function(){ alert("Button"+i);}这个匿名函数中没有i,根据作用域链,所以到buttonInit函数中找,此时i的值为4,所以弹出”button4“。

with语句

说到作用域链,不得不说with语句。with语句主要用来临时扩展作用域链,将语句中的对象添加到作用域的头部。

看下面代码

 

person={name:"yhb",age:22,height:175,wife:{name:"lwy",age:21}};  
with(person.wife){  
    console.log(name);  
}  

 

with语句将person.wife添加到当前作用域链的头部,所以输出的就是:“lwy".

with语句结束后,作用域链恢复正常。

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值