1.作用域概述
通常来说,一段程序代码中所用到的名字并不总是有效和可用的,而限定这个 名字的可用性的代码范围就是这个名字的作用域,作用域的使用提高了程序逻辑的局部性,增强了程序的可靠性,减少了名字冲突
1.1.js作用域(es6之前)分为: 全局作用域 局部作用域
1.2.全局作用域 :整个script标签 或者是一个单独的js文件
var num = 10 ;(这一个标签是写在全局作用域里面 这个变量名是可用的 称之为全局作用域)
1.3.局部作用域(函数作用域):在函数内部就是局部作用域,这个代码的名字只在函数内部起效果和作用
var num = 10 //全局作用域
function fn(){
//局部作用域
var num = 20 ; //局部下的num和全局下的num是不冲突的因为输出的不一样
console.log(num) //20
}
fn() //切记调用
console.log(num) // 10
2.变量作用域
在js中,根据作用域的不同,变量可以分为俩种:全局变量,局部变量
2.1.全局变量:在全局作用域下的变量 在全局下都可以使用(在函数外部定义的变量)(3.特殊情况注意一下:如果在函数内部,没有声明直接赋值的变量也属于全局变量)
var num=10;
console.log(num);//可以打印 10
function fn(){ //函数
console.log(num)//也是可以打印的 10
}
fn()
console.log(aru) //4.aru is not defined 不能使用
2.2.局部变量:在局部作用域下的变量 或者可以理解为在函数内部的变量就是局部变量(在函数内部定义的变量)(注意:函数的形参也可以看做是局部变量 4.aru是一个形参)
function fun(aru){
var num1 = 10; //1.num就是局部变量 特点就是只能在函数内部使用
num2 = 20; //3 . 如果在函数内部,没有声明(不适用var)直接赋值的变量也属于全局变量
}
fun();
console.log(num1); //2.num is not defined 报错 所以说外部是不能使用的
console.log(num2); //3. 20 如果在函数内部,没有声明直接赋值的变量也属于全局变量
2.3.区别:从执行效率来看全局变量和局部变量
(1)全局变量在任何一个地方都可以使用,只有浏览器关闭的时候才会销毁,比较占内存资源
(2)局部变量 当我们程序执行完毕就会销毁,比较节约内存资源
3.作用域链
3.1.只要是代码,就至少有一个作用域
var num = 10; //全局作用域
3.2.在函数内部的叫做局部作用域
var num = 10;
function fun(){ //外部函数
var num = 20;
function fn(){//3.3.在fun函数里面有生成了一个fn函数 作用域里面诞生了一个新的作用域 内部函数
console.log(num);//3.4.执行是20还是10呢 20 用链式查找决定 它会往上一级找有没有num 一层一层的找就是链式查找
}
fn()
}
fun()
3.3.如果函数中还有函数,那么在这个作用域中就有可以诞生一个作用域
3.4.根据在内部函数可以访问外部函数变量的这种机制,用链式查找决定哪些数据能被内部函数访问,就称为作用域链(简单理解就是就近原则,谁离的近就执行谁)
案例1:
function f1(){ //1 可以称为0级链
var num = 123; //2 可以称为1级链
function f2(){ //2 可以称为1级链
console.log(num); //3 可以称为2级链 123
}
f2()
}
var num = 456; //1 可以称为0级链
f1();
案例2:
var a = 1;
function fn1(){
var a = 2;
var b = '22';
fn2();
function fn2(){
var a = 3;
fn3();
function fn3(){
var a = 4;
console.log(a); //4
console.log(b); //22
}
}
}
fn1();
4.预解析
.1问
console.log(num) //num is not defined 没有声明没有赋值
.2问
console.log(num) //undefined 坑1
var num = 10;
~ 相当于执行了以下代码
var num; //把var提升到当前作用域的最前面 但是不提升赋值(num = 10)
console.log(num); //只声明不赋值 所以输出就是 undefined
num = 10;
.3问
//fn();
function fn(){
console.log(11) //fn()前后调用都是11
}
fn();
.4问
//fun() //var fun变量是不可以当函数使用的 function
var fun = function(){
console.log(22) //22
}
fun()
~相当于执行了以下代码
var fun; //把var提升到当前作用域的最前面 声明了一个变量没有给值
fun();
fun = function(){ //函数表达式
console.log(22) //22
}
//fun(); //当它赋完值以后它就有函数了 就可以调用了(调用是写在函数表达式声明的下面)
什么是预解析
1.js代码是由浏览器中的js解析器来执行的,js解析器在运行js代码的时候分为俩步:预解析和代码执行
(1).预解析 : js引擎会把js 里面所有的var 还有function 提升到当前作用域的最前面
(2).代码执行 : 按照代码的书写顺序从上往下执行
2.预解析分为 变量预解析(变量提升) 和 函数预解析(函数提升)
(1).变量提升:就是把所有的变量声明提升到当前的作用域最前面,不提升赋值操作
(2).函数提升:就是把所有的函数声明提升到当前作用域的最前面,不调用函数(函数表达式 调用必须写在函数表达式下面)
案例1:
var num = 10;
fun();
function fun(){
console.log(num); //undefined
var num = 20;
}
~相当于执行了以下代码
var num; //1.先把var进行提升 提升到当前作用域最前面
function fun(){ //2.var num变量 当前作用域是 function fun函数内部的就没有 这里把这个大的函数要提升拿过来
var num //4.把变量提升到当前作用域的最前面
console.log(num);
num = 20;
}
num =10; //3.依次写就行 正常代码
fun();
按照作用域链执行 首先有个var num 然后执行函数function 函数没有调用不执行 略过 往下走 num存了一个10 往下走 fun()调用函数在回头调用函数往function里面走 调用函数之后里面有个var num 再看console.log(num); 就近原则 那就是var num离得最近 var num只有num没有值 所以就是undefined
正确这样写
var num = 10;
function fun(){
var num = 20;
console.log(num)
}
fun()
案例2:
var num = 10;
function fn(){
console.log('1',num) //undefined
var num =20;
console.log('2',num) //20
}
fn()
~相当于执行了以下代码
var num;
function fn(){
var num
console.log('1',num) //undefined
num =20;
console.log('2',num) //20
}
num =10;
fn();
案例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 b;
var a;
b = 9
console.log(a) //undefined
console.log(b) //9
a = '123'
}
f1();
案例4:
f1();
console.log(c);
console.log(b);
console.log(a);
function f1(){
var a = b = c = 9;
console.log(a);
console.log(b);
console.log(c);
}
~相当于执行了以下代码
function f1(){ //1.因为没有变量所以就把函数提到前面 2.先打印函数里面的 因为函数提升到前面了
var a=9;b=9;c=9 //相当于 var a=9;b=9;c=9 b,c 直接赋值没有var声明当全局变量看(赋值了没有声明就是全局变量)
console.log(a); //9
console.log(b); //9
console.log(c); //9
}
f1(); //1.依次排过来
console.log(c);//9 因为b,c是全局变量任何地方都可以使用的
console.log(b);//9 因为b,c是全局变量任何地方都可以使用的
console.log(a);//defined 因为a是局部变量 外面是不可以调用的
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。