文章目录

目录

文章目录

一、let、var的区别

        1、作用域不同

        2、let不能在定义之前访问该变量,但是var可以在定义之前访问(let不会预解析)。 

        3、let不能被重新定义,但是var是可以的 

二、作用域

        1、什么是作用域呢??

        2、变量定义、使用、赋值机制,作用域链

        3、块级作用域和局部作用域区别

三、预解析

        1、什么是预解析??

        2、预解析的无节操

 



一、let、var的区别

        let、以及var都是声明变量的

        1、作用域不同

        var是函数作用域(伪全局作用域),而let是块级作用域。在块级作用域内声明的变量无法在块级作用域外面使用


        2、let不能在定义之前访问该变量,但是var可以在定义之前访问(let不会预解析)。 

                var声明的变量,变量提升了(预解析了), let不会预解析

console.log(a)//预解析只声明不复制 undefined
var a = 10//var 后面的变量,变量提升了(也就是预解析了)
console.log(a)//10
console.log(b)//报错(Uncaught ReferenceError: Cannot access 'b' before initialization),let声明的变量不能在定义(初始化)之前访问
let b = 20

        3、let不能被重新定义,但是var是可以的 

let a = 10
let a = "你好"//报错(Uncaught SyntaxError: Identifier 'a' has already been declared)let后面的变量不能重新定义,var可以
console.log(a)
var b = 10
var b = "你好"
console.log(b)

二、作用域

        1、什么是作用域呢??

                作用域:作用域就是变量(变量名、函数名)生效的区域,作用域又分为全局作用域(window就是全局作用域)以及局部作用域(私有作用域,函数里面就是私有作用域)。

        2、变量定义、使用、赋值机制,作用域链

                变量定义:变量定义在哪一个作用域里面,就只能在当前作用域(包括子级作用域)里面使用,上一级作用域无法使用

                变量使用:当需要使用一个变量,会首先在自己的作用域里面查找,如果有就直接使用,没有就去上一级作用域查找,如果还没有,再去上一级查找,直到查找到window(全局作用域)依然没有,就报错 (Uncaught ReferenceError: xxx is not defined) 

                作用域链:就是变量一层一层向上查找的过程

                变量赋值:当需要给一个变量赋值时,会在自己作用域里面查找,有就赋值(注意和变量声明区分开),没有就去上一级查找,直到window都没有,就把这个变量定义为全局变量再赋值    

// 全局作用域
var a //在全局作用域声明一个a变量
a = 5//变量赋值 
c //变量声明必须加上关键词let var const(常量),没有就报错
d = 6//变量赋值会先查找(查找到window)如果没有,就声明(相当于使用var,但是不会预解析)再赋值
function fn() {
    var b=6//私有作用域声明一个变量
    console.log(a)//变量使用,在自己作用域查找,没有去上一级查找(作用域链),找到了a为5返回5
}
fn()
console.log(b)//错误全局中没有b变量,b变量是定义在function里面的,是fn私有的,全局调用报错

        3、块级作用域和局部作用域区别

                块级作用域:只要{}没有和函数结合在一起, 那么应该"块级作用域"

                局部作用域:函数后面{}中的的作用域, 我们称之为"局部作用域"

                1、在块级作用域中通过var定义的变量是全局变量

                2、在局部作用域中通过var定义的变量是局部变量

                3、let只要在{}里面就是局部变量

                4、无论是在块级作用域还是在局部作用域, 省略变量前面的let或者var就会变成一个全局变量(省略之后,赋值号必须要,不然报错表示直接使用not defined,省略之后不会进行预解析,相当于给window增加了一个属性名和属性值)

//块级作用域{}
{
    var a = 1; // 全局变量
    let b = 2; // 局部变量
    c = 3; // 全局变量
}

//函数后的{} 局部作用域
function test() {
    console.log(d)//undefined
    var d = 4; // 局部变量
    let e = 5; // 局部变量
    console.log(f)//报错(Uncaught ReferenceError: f is not defined)
    f = 6; // 全局变量 不会预解析
    console.log(f)//6 赋值了
}
console.log(a)//打印1
console.log(b)//报错
console.log(c)//打印3
test()//执行函数test,里面的变量才会预解析,将de解析为局部变量,f为全局变量,(变量污染,里面的变量会污染全局),不执行f变量会出错
console.log(d)//报错
console.log(e)//报错
console.log(f)//打印6

三、预解析

        1、什么是预解析??

                在初始化页面加载时,js会先加载function以及变量,但是不会加载变量赋值的过程。预解析是在加载这个页面就进行了(全局预解析),之后再加载代码。

                变量预解析以及函数预解析,函数声明以及变量声明会提到当前作用域前面,但是不会调用和赋值

        当变量名和函数名重名时,会预解析函数(权重大),函数名不要和变量重名,重名以函数为准

                全局作用域预解析:在页面打开就进行了,只解析全局的内容

                私有作用域预解析:执行的时候才会内部预解析,函数内部预解析,只属于函数内部

        问题:一旦函数的形参和定义的私有变量重名,是先预解析还是先形参赋值?

                因为函数是单独进行预解析的,所以在函数执行的时候,会先进行形参赋值,然后再进行预解析 

fn()//打印,函数预解析权重大于变量预解析
console.log(fn)//这里的fn是一个函数
var fn = 66
console.log(fn)//fn赋值为66
fn()//报错(Uncaught TypeError: fn is not a function),fn已经变成一个变量了,不是函数
function fn() {//该fn函数是声明式函数
    console.log("我是fn函数")
}
fn1()//赋值式函数不能先调用,因为预解析时,将fn1当成了一个变量,没有赋值
var fn1 = function(a){//该fn1函数是赋值式函数
    console.log("我是fn1函数")
    console.log(a)//函数形参和私有变量重名,先进行形参赋值,再预解析,所以打印4
    var a = 10
    console.log(a)//打印10
}
fn1(4)//打印

/* 
        1、预解析函数fn 
        2、变量fn预解析 然后fn1预解析
        3、fn(),函数执行,内部预解析
        4、打印fn函数(函数名加括号表示执行,不加括号表示函数)
        5、fn赋值为66
        6、打印fn,66
        7、执行fn()函数,错误(以下步骤出现错误,直接忽略,可以加try catch)
        8、fn1() 错误,没有这个函数,但是有fn1变量,打印fn1不会报错undefined
        9、fn1赋值为函数,赋值式函数
        10、fn1(4),函数执行,内部预解析
            a、给形参a传递参数4,(形参赋值)
            b、预解析里面的变量a
            c、打印我是fn1函数
            d、4
            e、变量a赋值
            f、打印10        
    */

        2、预解析的无节操

                1.预解析的时候不管你的条件是否成立,都要把里面的代码进行预解析。

                2.预解释的时候只预解释”=”左边的,右边的值,不参与预解析

                3.自执行函数:定义和执行一起完成了。

                 4.函数体中return下面的代码虽然不再执行了,但是需要进行预解析;

                5.函数声明和变量声明都会被提升。函数名不要和变量重名,重名以函数为准,在预解析的时候,如果名字已经声明过了,不需要从新的声明,但是需要重新的赋值;

 

Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐