作用域原理揭秘,你真的了解作用域吗

首先,啥是作用域,作用域就是一个变量可被访问的范围,也就是说,你定义了一个变量,我在哪里可以访问到它,哪里就是它的作用域,全局可以访问就是全局,函数体内可以访问就是函数体内。

在这里插入图片描述
然后,es6新加了let和const 我们先不讨论,因为这俩的作用域很好判断,我们讨论var,也就是这个坑最多,面试经常问的东西

我们要明确,var是没有块级作用域的!

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

猜猜输出啥,输出undefine,那么为啥输出这个呢,中间经过了什么呢

这就要涉及到第一个知识点
var声明的变量会有变量提升,就是会把声明提升到函数内部最前面,赋值操作在原位置
然后就引出了第二个概念函数作用域
就是说,函数内部的变量,在函数体内任何位置都是有定义的!但是只有赋值之后才有值,懂了吧,

我们可以看到,由于函数作用域的特性,局部变量在整个函数体始终是由定义的,我们可以将变量声明”提前“到函数体顶部,同时变量初始化还在原来位置。

为什么说Js没有块级作用域呢,有以下代码为证:

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

说到这里,有一个非常需要注意的问题,快作用域和函数作用域

var a=10;
	function fun()
	{
    
    
		var a=100;
		a++;
		console.log(a);
	}
	fun();//101

	console.log(a);//10

观察,为什么第一个修改了全局里面的name,但是第二个没有修改全局里面的a呢,因为第一个使if大括号,第二个是函数大括号,有函数作用域,里面定义的变量是独立于函数体外的
你以为加一个大括号就是块级作用域了吗,错,只有放在函数体内,才会实现块级作用域的功能

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

将声明s中的var去掉。
程序会报错还是输出“ifscope"呢?

让我揭开谜底吧,会输出:”ifscope"

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

扫描二维码关注公众号,回复: 12395056 查看本文章

当使用var声明一个变量时,创建的这个属性是不可配置的,也就是说无法通过delete运算符删除

var name=1 ->不可删除

sex=”girl“ ->可删除

this.age=22 ->可删除

三:作用域链

name="jack";
function t(){
    
    
    var name="mary";
    function show(){
    
    
        var name="tom";
        console.log(name);
    }
    function shows(){
    
    
        console.log(name);
    }
    show();
    shows();
}
t();

分析:
当调用t函数show指向时,将自己的函数环境压入栈中,该函数内部有name所以不需要上级索引,直接输出

当调用shows函数时,函数环境入栈,但是本函数里面没有name,所以将上一级函数环境入栈,也就是t函数,使用里面的name,注意不是show函数,而是父函数

这就是作用域链

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

Button1 Button2 Button3 当文档加载完毕,给几个按钮注册点击事件,当我们点击按钮时,会弹出什么提示框呢? 很容易犯错,对是的,三个按钮都是弹出:"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语句结束后,作用域链恢复正常。

猜你喜欢

转载自blog.csdn.net/weixin_43124546/article/details/110871530