作用域和预解析
1.js作用域:变量在某个范围内起作用和效果(目的:提高程序的可靠性和减少命名冲突)
2.分类:全局作用域、局部作用域
2.1.全局作用域:整个script标签或者一个单独js文件
2.2.局部作用域:函数内部就是局部作用域,只在函数内部起作用
3.变量分类:全局变量、局部变量
3.1根据作用域的不同,变量可分为两种:全局变量、局部变量
3.2全局变量:在全局作用域下的变量。
3.3局部变量:在局部作用域下的变量。
注意:
如果在函数内部没被声明直接被赋值的变量也是全局变量(不建议使用)
函数的形参也可看做局部变量
4.区别:
(1)全局变量:在任何一个地方都能使用,只有浏览器关闭时才会销毁,比较占内存
(2)局部变量:只在函数内部使用,当其所在的代码块被执行时,会被初始化;当代码块运行结束后,就会被销毁,因此更节约空间。
5.js块级作用域:
5.1.{}---if{}、for{}
5.2.//在Java中,块级作用域定义的变量不能在外面调用
if(x){
int num = 10;
}
//此时在外面调用会报错
但是现阶段js没块级作用域可以用console.log(num)调用
6.作用域链:
内部函数访问外部函数的变量,采取链式查找的方式来决定取哪个值。
(如果多层函数嵌套,内部函数访问上一级外部函数的变量时,如果有该变量则调用,如果无则往上一级匹配,直到匹配成功。也就是就近原则)
案例:
var num = 10; //后匹配
function fn() {
var num = 20; //先匹配
function fun() {
console.log(num); //输出20
}
fun();
}
fn();
练习1:看看这段代码输出为几多?
function f1() {
var num = 123;
function f2() {
console.log(num);//123,就近原则
}
f2();
}
var num = 456;
f1();
预解析
1、抛出问题:
//预解析
//问1:
console.log(num);
var num = 10; //undefined
//问2:
fn(); //11
function fn() {
console.log(11);
}
//fn()放自定义函数前后都行
//问3:
fun();
var fun = function () {
console.log(22);
}// fun is not a function
2、分析:
2-1、js引擎运行js分两步:预解析和代码执行
(1)预解析:js引擎会把js里面的所有var 还有function提升至当前作用域的最前面。
(2)代码执行:代码顺序从上往下执行
2-2、预解析:变量预解析(变量提升)、函数预解析(函数提升)
(1)变量提升:把所有变量声明提升至当前作用域最前面,不提升赋值操作
//问1:
console.log(num);
var num = 10; //undefined
//相当于执行:
var num;
console.log(num);
num = 10;
//问3:
fun();
var fun = function () {
console.log(22);
}// fun is not a function
//相当于执行:
var fun;
fun();
fun = function(){
console.log(22);
}
注意:因此函数表达式的调用必须写在函数表达式的下面
(2)函数提升:把所有函数声明提升至当前作用域最前面,不调用函数
问2:所以fn()放函数前后都行·
4,案例:
(1)案例1:
//案例1:
var num = 10;
fun();
function fun() {
console.log(num);
var num = 20;
}//undefined
//相当于:
var num;//变量提升
function fun() {//函数提升
var num;//函数内变量提升
console.log(num);//就近原则,num声明未被赋值则输出undefined
num = 20;
}
num = 10;
fun();
(2)案例2:
//案例2:
var num = 10;
function fn() {
console.log(num); //undefined
var num = 20;
console.log(num); //20
}
fn();
//相当于:
var num;
function fn() {
var num
console.log(num); //undefined
num = 20;
console.log(num); //20
}
num = 10;
fn();
(3)案例3:
//案例3:
var a = 18;
f1();
function f1() {
var b = 9;
console.log(a); //undefined
console.log(b); //9
var a = "123";
}
//相当于:
var a;
function f1() {
var a;
var b;
b = 9;
console.log(a); //undefined
console.log(b); //9
a = "123";
}
a = 18;
f1();
(4)案例4:
//案例4:
f1();
console.log(c);//9
console.log(b);//9
console.log(a);//a is not defined
function f1() {
var a = b = c = 9;
console.log(a);//9
console.log(b);//9
console.log(c);//9
}
//相当于:
function f1() {
var a;//局部变量
a = b = c = 9;
//相当于 var a=9; b=9;c=9;b和c直接赋值并未声明,当全局变量看
//若要集体声明则为 var a=9,b=9,c=9;
console.log(a);//9
console.log(b);//9
console.log(c);//9
}
f1();
console.log(c);//9
console.log(b);//9
console.log(a);//a is not defined
补充:
有关arguments的使用
//arguments的使用
function fn() {
console.log(arguments); //里面存储了所有传递过来的实参
console.log(arguments.length);
}
fn(1, 2, 3);
//arguments是伪数组,并不是真正意义上的数组
//1.具有数组的length属性
//2.按照索引的方式进行存储
//3.他没有真正数组的一些方法pop()、push()等等
//Arguments { 0: 1, 1: 2, 2: 3, … }
//3