JavaScript
二、预解析和作用域
2.1 预解析
在所有代码执行之前,对代码进行通读并解释(只是把代码当作一个文档)
当有 函数 和 变量名重名的时候,在预解析阶段以函数为准(函数的优先级更高)
扩展:报错信息
Uncaught TypeError : fn is not a function
=>要考虑,我前面的代码是不是用过fn这个变量了
预解析解释了什么?
1.var关键字
此时分别输出: undefined 和 100
2.声明式函数
此时都正常输出
注意:匿名式函数按var规则来解析
报错,因为此时fn是已定义而未赋值,是undefined,不是一个function,无法按function来执行。
预解析案例:
!!!笔试可能会有:
1.这段代码执行情况:执行到第二个fn报错
2.报错信息是什么:fn is not a function
预解析的无节操
1.if只决定赋值,不决定预解析;if条件不管是不是成立,里面的代码都会进行预解析
2.return后面的代码虽然不会执行,但是仍会预解析
if(true)输出:undefined 100
if(false)输出: undefined undefined
写代码的建议
通过预解析得知:
+ 函数名 不要和 变量重名
+ 声明式函数可以先调用,尽量不要先调用
+ 尽量使用 匿名函数(赋值式函数) 来定义
建议:
1.变量名
+ 以名词为主
+ price
+ goods
+ 尽可能的两个到三个单词
+ userName
+ userInfoAge
2.函数名
+ 以功能为主
+ getRandomColor()
+ setGoodsPrice()
+ clickHandler()
2.2 作用域
作用域:变量(变量名,函数名)生效的范围
两种:
1. 全局作用域
+ 打开一个页面就是一个全局作用域
+ 全局作用域,叫做window
2. 私有作用域(局部作用域)
+ 只有函数生成私有作用域
+ 每一个函数就是一个私有作用域
作用域的上下级关系
+ 你的函数写在哪一个作用域下
+ 你就是谁的子级作用域
作用域的上下级关系是干嘛的
+ 为了确定变量的使用范围
+ 三个机制
1. 变量的定义机制
+ 有 var 关键字
+ 声明式函数
2. 变量的使用机制
+ 你需要拿到某一个变量的值来使用
3. 变量的赋值机制
+ 一定要有赋值符号
2.3 变量的三种机制
1. 变量的定义机制
2. 变量的使用机制
例1:
输出200
例2:
输出undefined
例3:
也输出undefined,因为形参就相当于函数内部定义的私有变量
3. 变量的赋值机制
例1:
此时的num为全局变量
例2:
输出:
例3:
例4:
输出:
例5:
例6:
输出:
2.4 作用域和预解析
案例1
//案例1.1
var a = b = 20;
a = 10;
b = 10;
console.log(a); //10
console.log(b); //10
/*
等于号是赋值
=> 赋值符号是从右向左赋值
预解析
1. var a
代码执行
1. b = 20
=> 变量赋值
=> 当一直到window都没有b的时候,会把b定义为全局变量
2. a = b
=> 变量使用 和 赋值
=> 使用 的是b
=> 赋值 的是a
3. a = 10
4. b = 10
*/
//案例1.2
var a = b;
a = 10;
b = 10;
console.log(a);
console.log(b);
/*
预解析
1. var a
代码执行
1. a = b
=> 变量使用 和 赋值
=> 使用 的是b,b没有这个变量
=> 赋值 的是a
=> 直接报错
*/
案例2
//案例2.1
fn();
var fn = 100;
function fn(){
fn = 200;
}
console.log(fn); //100
/*
预解析
1. var fn
2. function fn(){}
预解析结束时,fn是一个函数
代码执行
1. fn()
=> fn =200
=> 给全局的fn赋值,赋值为200
2. fn = 100;
=> 给全局的fn赋值,赋值为100
3. console.log(fn);
=> 100
*/
//案例2.2
fn(); //第一次执行后,把全局的fn赋值为200
fn(); //把200当作一个函数来执行,报错 fn is not a function
var fn = 100;
function fn(){
fn = 200;
}
console.log(fn);
案例3
function fn(){
var num = 100;
function fun(){
//变量的使用和赋值
//预解析,fun里面会预解析一个num
//使用num的值,赋值给num
//使用的时候,num就是undefined
//把undefined赋值给num
var num = num;
console.log(num) //undefined
}
fun();
}
fn();
2.5 预解析的阶段
1. 全局预解析
=> 会在页面打开的时候就进行了
=> 只解释属于全局的内容
例子:
此时不管fn()有没有执行,var a和function fn(){}都已经预解析了
2. 私有作用域预解析
=> 当函数执行的时候进行预解析
=> 因为函数是单独进行预解析,所以在函数执行的时候,先进行形参赋值,再进行预解析
=> 函数内部的预解析,只属于函数内部
注: var b只有在fn()执行时才会被预解析;有几个fn()被解析几次。
由函数执行的时候,先进行形参赋值,再进行预解析可得知,在写代码时:
1.不要在一个函数内部定义一个和该函数的形参重名的函数
2.全局变量的定义尽量不要写在函数内部
3.让一个变量跨函数使用
=> 可以把多个函数内部使用的变量定义在几个函数的外面,在函数内部只是进行操作