浅谈JS作用域

一、js作用域概念—预解析规则,表达式

域:指的是一个空间、范围、区域

作用:通常指读和写

所以

作用域:指的是在一个范围内进行读或写的操作

浏览器中对js代码进行操作的是js解析器

js解析器的作用是:

1.“找一些东西”(var关键字、函数、参数)

var a=1;
function fn1(){
alert(2);
}

在上面的代码中,

a=未定义;

即:所有变量在正式运行之前都被赋了一个值:未定义

fn1 = function fn1(){
alert(2);
}

即:所有的函数在正式运行代码之前都是整个函数块

注意:在js预解析中,遇到重名变量和函数时,只留函数。

2.逐行解读代码

通过表达式解读代码( = + * / % ++ – ! Number() 参数)
解析代码的过程是从仓库里找东西

注意:表达式可以修改预解析内的值

二、全局与局部作用域解析以及作用域链

域的形成在js当中有两种

1.script标签

当中含有全局变量、全局函数(window)
读取的方式是自上而下

2.函数(作用域链)

读取的方式是由里到外
在js高程中有介绍道:作用域链的用途,是保证对执行环境有权访问的所有变量和函数的有序访问(其实和我总结的一样啦~~)
下面我们来看一个代码:

例1

alert(a);   //function a(){alert(4);}
var a=1;
alert(a); //1
function a(){alert(2);}
alert(a);  //1
var a=3;
alert(a);  //3
function a(){alert(4)}
alert(a);  //3  //typeof(a) 为number
a();  //报错

解析:
第一步“找” 首先解析器先找关键字找到var a=未定义,然后又找到函数a=function a(){alert(2);},则覆盖原来的a=未定义;然后又找到a =未定义;无法覆盖,继续往下,找到a=function a(){alert(4)};现在在仓库里存入a=function a(){alert(4)};

第二步“读”从上往下看,读到alert(a),从仓库里找到刚才存入的a=function a(){alert(4)},所以输出;然后再往下第二行看见’=‘,则覆盖原来的函数,修改了原来仓库里的值使a=1;所以下一步输出a=1;再往下,函数中没有关键字,不修改仓库里的值,继续往下输出a=1;同理看见=;修改为a=3,然后输出。一直到最后a的值也是3。
但是当调用a();这个函数时,会报错,因为在仓库里a是一个变量不是一个函数。

再举一个例子:

例2

var a=1;
function fn1(){
  alert(a);   //a=未定义
  var a=2;
}
fn1();
alert(a);  //a=1

解析:
1.存入仓库里的是

a=未定义

fn1()=function fn1(){
alert(a);
var a=2;
}

自上而下往下读时,第一行有=;所以a=1;第二行函数不管,一直到调用fn1时,进入函数内部;

注意1:函数内部也是类似于作用域,分为两步;找东西和逐行读代码

进入函数内部之后,找到var a=.. ,所以函数内部仓库a=未定义;现在开始读代码,alert输出a=未定义;再往下,遇到=,给a赋值a=2;跳出函数继续往下,alert(a);

注意2:函数内部的为局部变量,现在浏览器访问到全局的仓库里找到a=1,所以输出a=1;

*局部作用域可以访问全局

同理,我再将上边的代码修改一下(将函数内部的var删除):

例3

var a=1;
function fn1(){
  alert(a);   //a=1
   a=2;
}
fn1();
alert(a);  //a=2

解析:与原来不同的是,函数内部仓库里找不到a存的值,或者换句话说,没有存入a,则需要从外部调取,所以a=1;同时函数内部修改了a的值,改为a=2;值得一提的是,此时修改的是全部变量的值,所以当函数调用完之后输出的是a=2

例4

var a=1;
function fn1(a){
  alert(a);  //a=未定义
  a=2;
}
fn1();
alert(a);   //a=1

解析:第一步,a存入仓库:a=未定义,然后开始读代码,读取第一行使a=1;再读入函数调用,调用函数时发现函数调用使用了参数,参数a=var a…将其存入函数内部仓库,所以函数内部输出alert(a)时,a=未定义,下一步修改函数内部a=2,跳出函数;alerta(a)时,调用的是全局变量所以输出a=1;

三、调用函数局部是数据,全局声明以及for嵌套中i的取值

例5

var a=1;
function fn1(a){
  alert(a);
  a=2;  //a=1
}
fn1(a);
alert(a);  //a=1

解析:第一步,a存入仓库:a=未定义,然后开始读代码,读取第一行使a=1;再读入函数调用,调用函数时发现函数调用使用了参数,参数a = var a = 1;因为fn1(a)中的a来自全局,所以当读取函数内部的alert(a)时a=1;下一步修改函数内部a=2,跳出函数;alerta(a)时,调用的是全局变量所以输出a=1;

我们需要始终记住作用域的特点:先解析再执行

当然,如果我们想获取函数内部的值,就是获取局部变量的值
可以通过下面两个办法:

1.利用全局变量赋值获取

例6

var str ='';
function a(){
  a='999';
  str =a ;
}
alert(str);

2.通过函数调用

例7

function fn2(){
  var a ='999';
  fn3();
}
fn2();
function fn3(d){
  alert(d);
}

例8

alert( fn1 );       

var a = 1;
function fn1(){
    alert(123);
}

if( true ){

}

firefox不能对下面的函数进行预解析

对于for或者if嵌套,在js高程里称作“没有块级的作用域”,上面解释道:以for语句为例,由for创建的变量i即使在for循环执行结束后,也会依旧存在于循环外部的执行环境中。

例8

for(var i=0;i<10;i++){
  dosomething();
}
alert(i)  //i=10

猜你喜欢

转载自blog.csdn.net/welkin_qing/article/details/80673682