[JavaScript]JavaScript作用域链、变量提升、|变量|函数|参数|变量提升|的优先级

本文深入探讨JavaScript中变量提升、作用域链、let与const特性,通过具体实例解析变量声明、赋值顺序及优先级,帮助理解全局变量声明方式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、题目代码:

    var bar=1;
    function test(){
        console.log(bar);
        var bar=2;
        console.log(bar);
    }
    test();
    //会输出什么?

答案和解析在下面














二、答案:
在这里插入图片描述
三、解析:
js寻找变量先是在自己的域找,找不到了再去外层找
所以当

    var bar=1;
    function test(){
        console.log(bar);
    }
    test();

这种情况会输出1

由于var声明变量会有变量提升的现象,所以题中的情况等价于

    var bar=1;
    function test(){
		var bar;
		//虽然题中没有这句,但是用var定义变量会进行变量提升
		//会隐式的声明变量,也就相当于是有这个语句了
        console.log(bar);
        var bar=2;
        console.log(bar);
    }
    test();

所以很容易得出,在第一个console.log执行时,bar是undefined
第二个console.log自然就是输出上一行在这个域中赋值过的bar
值为2

   var bar=1;
    function test(){
        console.log(bar);
        var bar=2;
        //如果题目中这里用let或const就会报错:
		//Cannot access 'bar' before initialization
		//let和const不会变量提升,而上一行用了bar,且在这个域找到了bar
		//而bar在声明前就被调用了,所以会报错
        console.log(bar);
    }
    test();

同考点题再练(答案在最下面):

    function c(){
    var b=1;
    function a() {
        console.log(b);
        var b =2;
        console.log(b);
      }
      a();
      console.log(b);
    }
    c();
    //答案undefined 2 1

四、总结:
1.由于变量提升bar的赋值可以写于声明之前,而let,const则不行
let和const必须先声明再赋值或者声明同时赋值

    a=3;
    console.log(a); //3
    var a;

	b=3;
    console.log(b);//Cannot access 'b' before initialization
    let b;
	
	let c=3;
    console.log(c);//3

2.var可以重复声明,let和const不能重复声明

   	let n;
	let n=1;//Identifier 'n' has already been declared
	
	var p=1;
	var p=2;//不会报错

3.优先级:变量>函数>参数>变量提升

    function fn(bar){
        var bar=2;//****输出结果来自这里
        console.log(bar);
        function bar(){
            return "函数"
        }
    }
    fn(1);
    //输出结果为2,说明变量优先级最大
    function fn(bar){
        console.log(bar);
        var bar=1;
        function bar(){//****输出结果来自这里
            return "函数"
        }
    }
    fn(2);
	//输出结果为ƒ bar(){return "函数"},
	//说明函数优先级大于参数和变量提升
    function demo(bar){
        console.log(bar);
        var bar=2;
    }
    demo(1);//****输出结果来自这里
    //输出结果为1,说明参数优先级大于变量提升
    function fn(bar){
        var bar;
        console.log(bar);
        bar=2;
    }
    fn(1);//****输出结果来自这里
    //结果输出1,说明变量提升相当于这种写法
    function fn() {
        return "1"
    }
    console.log(fn());  //结果是3,对于函数来说,后者覆盖前者
                        //函数声明的位置可以放在执行语句后面
    function fn() {
        return "2"
    }
    function fn() {
        return "3"
    }
    var fn=function (){//fn本质上是个变量
        return "1"
    }
    function fn() {//fn本质上是个函数
        return "2"
    }
    console.log(fn());  //结果是1,变量fn优先级大于函数fn
              
    function fn() {
        return "2"
    }
    console.log(fn);//输出2,函数优先级大于变量提升
    var fn=function (){
        return "1"
    }

4.全局变量
因为,在js中,如果某个变量没有var声明,会自动移到上一层作用域中去找这个变量的声明语句,如果找到,就使用,如果没找到,就继续向上寻找,一直查找到全局作用域为止,如果全局中仍然没有这个变量的声明语句,那么自动在全局作用域进行声明,这个就是js中的作用域链,也叫变量提升
全局变量的三种声明方法:

<script>
var a=1;//function外部定义

window.b=2;//window.定义
window.jQuery = window.$ = jQuery;
//比较典型的比如JQuery1.5中最末一句

function fn(){
	c=3;//function内部直接给标识符赋值定义
}
</script>

五、知识巩固

    function Foo() {
        getName=function(){console.log(1);}
        return this;
    }
    Foo.getName=function(){console.log(2);}
    Foo.prototype.getName=function(){console.log(3);}
    var getName=function(){console.log(4)}
    function getName(){console.log(5)}
	//分别输出什么
    Foo.getName();
    getName();
    Foo().getName();
    getName();
    new Foo().getName();















答案与解析:

    function Foo() {  
        getName=function(){console.log(1);}
        //在函数内标识符赋值,所以这个getName是全局变量
        return this;//这个this就是指window
    }
    Foo.getName=function(){console.log(2);}
    Foo.prototype.getName=function(){console.log(3);}
    //Foo.prototype是window,所以这个getName也是全局变量
    var getName=function(){console.log(4)}
    //这个getName在函数外声明也是全局变量
    function getName(){console.log(5)}

    Foo.getName();//2   执行foo对象的getName
    getName();//4		变量优先级大于函数,所以是4不是5
    Foo().getName(); //1 
    //因为这里先执行了Foo()相当于执行了 
    //getName=function(){console.log(1);}
    //return this;
    //此时getName=function(){console.log(1);}就覆盖了之前所有的全局变量getName
    //而Foo() return的是window,所以这里输出的就是最新的window.getName()
    //也就是输出1
    getName();//1		执行全局变量getName
    new Foo().getName();//3   Foo原型中的getName
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值