目录
文章目录
一、let、var的区别
1、作用域不同
2、let不能在定义之前访问该变量,但是var可以在定义之前访问(let不会预解析)。
3、let不能被重新定义,但是var是可以的
二、作用域
1、什么是作用域呢??
2、变量定义、使用、赋值机制,作用域链
3、块级作用域和局部作用域区别
三、预解析
1、什么是预解析??
2、预解析的无节操
let、以及var都是声明变量的
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
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)
作用域:作用域就是变量(变量名、函数名)生效的区域,作用域又分为全局作用域(window就是全局作用域)以及局部作用域(私有作用域,函数里面就是私有作用域)。
变量定义:变量定义在哪一个作用域里面,就只能在当前作用域(包括子级作用域)里面使用,上一级作用域无法使用
变量使用:当需要使用一个变量,会首先在自己的作用域里面查找,如果有就直接使用,没有就去上一级作用域查找,如果还没有,再去上一级查找,直到查找到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私有的,全局调用报错
块级作用域:只要{}没有和函数结合在一起, 那么应该"块级作用域"
局部作用域:函数后面{}中的的作用域, 我们称之为"局部作用域"
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
在初始化页面加载时,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
*/
1.预解析的时候不管你的条件是否成立,都要把里面的代码进行预解析。
2.预解释的时候只预解释”=”左边的,右边的值,不参与预解析
3.自执行函数:定义和执行一起完成了。
4.函数体中return下面的代码虽然不再执行了,但是需要进行预解析;
5.函数声明和变量声明都会被提升。函数名不要和变量重名,重名以函数为准,在预解析的时候,如果名字已经声明过了,不需要从新的声明,但是需要重新的赋值;