Js的作用域

1.函数作用域

以前做项目经常会用到Js,但是很多知识点都没有深入的研究,JS是一门非常难得语言(对于做后端的来说确实),今天看了下Js的作用域,感触非常深,在这里记录下。

首先看一段js代码:

var num="one";  
function t(){  
    console.log(num);  
    var num="two"  
    console.log(num);  
}  
t(); 
这段代码应该有人会认为输出:"one" "two" 。不过最后的结果是 "undefined" 和 "true" 。为什么呢?

应为JavaScript没有块级作用域,而是函数作用域,换句话说:JavaScript只有函数提供作用域。

再来看一段代码:

var num="one";  
if(true){  
    var num="two";  
    console.log(num)  
}  
console.log(num); 
都输出"two"。如果有块级作用域,if中的语句是不会改变全局变量第一个num的值得,所以说js是没有 块级作用域的。

所以到这里第一段代码应该很容易理解了。

那么下面这段代码应该也很容易理解:

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


2.变量作用域

function t(flag){  
    if(flag){  
        s="ifscope";  
        for(var i=0;i<2;i++)   
            ;  
    }  
    console.log(i);  
}  
t(true);  
console.log(s);
这段代码就是上面代码的修改版,其中把var申明给去掉了,但是这对结果肯定是没有影响的,

写过js的应该都知道没有var申明的变量都是全局变量,而且还是 顶层对象的属性。所以用console.log(window.s)也是输出"ifscope"。

当使用var声明一个变量时,创建的这个属性是不可配置的,也就是说无法通过delete运算符删除
var name=1    ->不可删除
sex=”girl“         ->可删除
this.age=22    ->可删除



3.作用域链

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.οnlοad=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“。


4.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语句结束后,作用域链恢复正常。

再看另外一段代码:

person={name:"yhb",age:22,height:175,wife:{name:"lwy",age:21}};  
with(person.wife){  
    console.log(name);  
} 
console.log(name);  
这段代码网上有人测试说会输出2个 "lwy",我试了下也是,后来发现原因:因为上面有个例子定义了全局变量nam="lwy",而且name 是 顶层对象的属性 这里取得之前那个name的值,真是巧啊。正确答案第二个输出应该是空!!!









评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值