高级js
0代码段概念
代码段就是指一个script标签,一个网页中可以有多个script标签,前面学过的jQuery中,我们就是在另一个script代码段中书写代码
代码段之间是相互独立的
js代码执行分为两个阶段,一个是预解析,一个是执行。预解析之后执行
1.预解析 (关于var的声明提前)
预解析时:注意两点:
第一点:函数的声明比变量的声明要更前(可以理解为函数为一等公民)
函数内部的变量声明提升到到函数内部最前面
第二点:变量的提升旨在声明部分,函数的提升不仅在声明,也赋值(整体)
<script>
// 预解析 关于var的声明提升
// 1.变量
console.log(a); //undefined
vara='jack'
console.log(a); //jack
// 相当于将 var a=‘jack’声明script代码段内部最前面
// 2.赋值变量函数(了解)
// fun() not a function //这里报错原因。他其实相当于一个函数表达式,声明提前,值并没有提前,加一个小括号就相当于undefined+()函数调用就会报错
varfun=function () {
console.log('我是函数1');
}
fun() //正确
// 3.具名函数
test()
functiontest() {
console.log('我是函数2')
}
test()
// 声明函数在声明变量代码段内部最前面,值与声明共同提升
</script>
2.var、let、const声明变量的区别
1.var声明(分为全局和局部作用域)
1.全局下var声明或不加var声明,都是全局变量,都会放到window上面,可以通过window.(打点的形式得到)
<script>
functionfn() {
a=100
}
fn()
console.log(a)//不使用var 或用var使用的全局变量都是全局变量,否会放到window上,
// 所以此时打印结果为:a的值:100
</script>
2.函数内部使用var 是局部变量,不能在外部调用
3.var可以声明相同变量,但是后者会覆盖前者
2.let声明(分为全局,局部和块级作用域)
1.let声明不会挂载在window上
2.let不可以重复声明相同名字变量
3.区分let的作用域:
全局:函数外部,script内部
局部:函数内部
块级:如if ( ) { } ,for(){ } 大括号内
<script>
leta=10
functionfn() {
letb=20
if (b>a) {
letc=30
console.log(a)
console.log(b)
console.log(c)
}
console.log(a)
console.log(b)
// console.log(c) //块级作用域无法访问,报错
}
fn()
console.log(a)
// console.log(b) //局部作用域无法访问,报错
// console.log(c) //块级作用域无法访问,报错
</script>
3.const声明(主要声明常量(不变的量))
1.和let一样拥有三个作用域
2.声明时必须给值
3.const声明的常量不会挂载到go上
总结:
项目中不要使用var,声明变量使用let 声明常量(不变的量)使用const
3.数据存储(栈和堆)
主要分为两个区:栈区和堆区
1.基本数据类型存储在栈区,(值存储)
2.复杂数据类型存储在堆区(址地址存储在栈区,值存储在堆区)
名词解释:
全局代码:函数外面的代码就是全局代码
函数代码:一个函数就是一个局部代码
1.EC(G):(Excution Content Globle)全局代码执行时,就会产生一个全局的执行上下文
2.EC (fn) :(Excution Content)函数代码执行时,会产生一个局部的执行上下文
3.ECS:(js引擎内部有一个执行上下文栈,Excution Content Stack,简称ECS,用于执行代码的调用栈)
EC(G)中包含两部分:
第一部分:在代码执行前,在parser转成AST的过程中,会将全局定义的变量、函数等加入到GlobalObject中,但是并不会赋值;这个过程也称之为变量的作用域提升(hoisting)
第二部分:在代码执行中,对变量赋值,或者执行其他的函数;
EC(fn)中包含三部分:
第一部分:在解析函数成为AST树结构时,会创建一个Activation Object(AO): AO中包含形参、arguments、函数定义和指向函数对象、定义的变量;
第二部分:作用域链:由VO(在函数中就是AO对象)和父级VO组成,查找时会一层层查找;
第三部分:this绑定的值:这个我们后续会详细解析;
代码执行过程:
js在执行代码时,首先执行全局代码,就会产生ECG,当我们调用一个函数,就会产生一个局部的执行上下文EC,这个局部的执行上下文也要入栈吗,当函数调用完毕,这个EC就要出栈,又进入ECG,当全局从代码执行完毕后ECG也要出战
执行上下文的作用:
提供数据,全局代码,肯定需要去全局的执行上下文中找数据
堆内存在js代码执行产生的全局对象(Go:Globle Object)
1.该对象中的所有作用域都可以访问,
2.在浏览器中等同于window,拥有window的属性和方法
3.全局变量和全局函数,都会挂载到window上
图例:
综合练习题
<script>
// 练习1:
// var a = 12; b = 13; c = 14
// function fn(a) { //函数内优先匹配自己的a 当前作用域有a,就匹配自己的a 这个值还是局部变量
// console.log(a); //a=10
// console.log(a, b, c) //a=10 b=13 c=14
// a = 100 //将形参a 重新赋值 这个值还是局部变量
// b = 200 //将b声明提前,全局
// console.log(a, b, c) // a=100,b=200 , c=14
// }
// b = fn(10) //b=一个函数,此时就是var b=函数,将变量声明提前,抵掉了b=13,此时b就是undefined
// console.log(a, b, c) //a 12 undefined 14
// 练习2
// var a = 10 //开辟一个内存空间
// var b = a //开辟一个新的内存空间
// console.log(a, b) //a=10,b=10
// b = 1
// console.log(a, b) //将b重新赋值,a=10,b=1
// 练习3:
// var a = [1, 2]
// var b = a
// console.log(a, b) //答案上同 [1,2],[1,2]
// b = [3, 4]
// console.log(a, b) //答案上同 [1,2],[3,4]
// 练习4:
// function fn() {
// var a = 10
// }
// fn()
// console.log(window.a) //走的是原型链 undefined
// console.log(a) //走的是作用域链 报错
// 练习5:
// console.log(a, b) //预编译,声明提升 值没有提升 undefined
// if (true) { //a=1
// var a = 1
// } else {
// var b = 2
// }
// console.log(a, b) //打印结果 1,undefined
// 练习6:(使用in判断元素是否再对象或数组/window上)
// var a
// console.log(a)
// if ('a' in window) {
// a = 200
// }
// console.log(a) //可以发现a是全局变量且挂载在window上,进入if,此时a的值打印结果为20
// 练习7:
// var a = 100
// function fn() {
// console.log(a)
// return
// var a = 110 //预编译 var a提升到函数内部最前面 所以打印结果undefined
// }
// fn()
// 练习8:
// var n = 100
// function fn() {
// n = 200
// }
// fn()
// console.log(n) //同样,预编译函数内n声明和值提前,打印结果n=200
// 练习9:
// function fn() {
// var a = b = 100 //这句话就相当于var a=100,b=100, a的声明提前,b是值和声明都提前
// }
// fn()
// console.log(a) //a报错
// console.log(b) //b=100
// 练习10:
// var n = 100
// function fn() {
// console.log(n) n=100
// }
// function gn() {
// var n = 200
// console.log(n) //n=200
// fn()
// }
// gn()
// console.log(n) n=100
// 练习10看下方图
</script>