JS作用域和预解析机制

1. 作用域

域:空间、范围、区域。。。
作用:读、写

alert(a);
var a=1;

结果为undefined

alert(a);
var a=1;

直接报错(因为没有找到var)
浏览器:JS解析器。
1)找一些东西:var function 参数
① 找到a=未定义(undefined),

所有的变量,在正式运行代码之前,都提前赋了一个值:未定义(undefined)。

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

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

以上叫做JS的预解析。注意两点:

  • 遇到重名的,只能留一个
  • 变量和函数重名,就只能留下函数。都是函数时,后面的覆盖前面的。

2)逐行读代码
表达式:= + . * / % ++ – ! ,参数…..Number();

  • 表达式会修改预解析的值
  • 函数声明不会改变仓库的值,只是会声明一下。
   alert(a); //未定义
   var a=1;
   function fn1(){
   alert(2);
   }

面试题

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
a();//报错;因为现在仓库里面是a=3;所以a()相当于3();

2. 全局与局部作用域解析、作用域链

script 全局变量 全局函数 是自上而下运行的,
函数,是由里到外
如下所示,上面的script找不到下面的值,下面的可以找到上面的。

<script></script>
<script></script>

面试题1

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

分析:
1)预解析:

  • 首先找到a=…(未定义)
  • 然后找到function fn1(){
    alert(a);
    var a=2;
    }

2)逐行解读代码

  • a=1;
  • 读到函数,因为只是一个函数声明,不是函数表达式,没有办法进行修改,所以仓库里面还是a=1;
  • fn1();读到函数调用,就是让函数执行,函数是一个局部的域,遇到域就要预解析和逐行解读代码。首先预解析a=…,然后正式读代码,次数的a和全局的a没有任何关系。
  • alert(a);找到的是全局的a,即为1.

面试题2

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

分析
1)预解析:

  • a=…(未定义)
  • 找到函数声明
function fn1(){
  alert(a);//undefined
  a=2;
}

2)逐行解读代码

  • a=1;
  • 函数声明不用动。
  • fn1();函数调用,又要预解析,逐行解读代码,弹出1。解释如下
此处需要注意,因为fn1()函数中找不到var,也找不到函数,所以预解析就结束了了,直接逐行解读代码。alert(a)的时候,因为找不到a,所以从子级跑到父级去找a(这个就就做作用域链,这里体现出了函数的由里到外)所以找到了,var a=1;弹出1,读到a=2的时候,因为局部的变量有能力改变外面的变量,所以,仓库中的a=1,变成a=2;
  • alert(a);弹出2

总结一下,之所以fn1(){…}函数中,前者弹出undefined,后者弹出1,是因为前者进行了函数预解析,所以按照一般情况进行。第二个因为没有走预解析,在里面没有找到东西,所以跑到外面去寻找变量。不过此处我的理解是,在fn1(){…}中因为a=2,前面没有加var,所以相当于全局变量,这样理解就比较清楚了。

面试题3

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

分析
1)预解析

  • var a=…
  • 找到函数声明

2)逐行解读代码

  • a=1;
  • 函数声明不用管
  • fn1();
首先找var a,没有找到,函数也没有,接着找参数,找到了(参数的本质就是一个局部变量),但是fn1();并没有传这个参数,所以这个参数相当于未定义。所以fn1(){...}的预解析就找到了一个参数 a =...。接着逐行解读代码,alert(a),读到的应该是预解析的参数,所以是undefined,读到a=2时,参数由未定义变成2,全局的变量a=1并没有改变
  • alert(a)读到应该是全局的a,所以值为1

面试题4

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

分析
1)预解析

  • var a=…
  • 找到函数声明

2)逐行读代码

  • a=1
  • 函数声明
  • fn1(a)函数的调用
a.预解析 var没有,函数没有,参数有,为a=...;
b.逐行读代码,参数相当于局部变量,所有从参数处读。参数也相当于赋值,此处a=1,但是这个1并不是全局的那个a,而是参数的那个a。紧接着这个局部的a由1变成2

-alert(a)指的是全局的a,为1

3. 调用局部数据、全局声明、for嵌套函数中i取值

1)局部可以访问外部,全局变量任何函数都可以改它。如下

var num=0;
function fn1(){
num++;
}
fn1();//1

2)外部不可以访问函数内部的作用域。如下所示,会报错

function fn1(){
 var a='大鸡腿';
}
fn1();
alert(a);

要向获取函数内的值
方法1:可以通过定义全局变量的方法如下所示

var str='';
function fn1(){
 var a='大鸡腿';
 str=a;
}
fn1();
alert(str);

方法2:局部的函数调用

function fn2(){
 var a='钻石';
 fn3(a);
}
fn2();//'钻石'
function fn3(a){
 alert(a);
}

3)作用域

函数的{}才是一个作用域,if(){}的{},for(){}中的{}不属于域。域的标志是先解析后执行

注意:
这里写图片描述

所以,想定义全局函数和全局变量尽量不要写在if或者for的{}里面

4)一道神奇的题

<input type="button" value="按钮1"/>
<input type="button" value="按钮2"/>
<input type="button" value="按钮3"/>

实现一个效果,点击任意一个按钮,是它们的背景色都变成黄色。以下代码没有问题

<script>
window.onload=function(){
 var aBtn=document.getElementsByTagName('input');
        for(var i=0;i<aBtn.length;i++){
         aBtn[i].onclick=function(){
           for(var i=0;i<aBtn.length;i++){
              aBtn[i].style.background='yellow';
           }
         }
 }
}
</script>

思考1:为什么不按照下面的方法写。分析:下面方法会报错。因为 alert(i);为3。for(var i=0;i

<script>
window.onload=function(){
 var aBtn=document.getElementsByTagName('input');
        for(var i=0;i<aBtn.length;i++){
         aBtn[i].onclick=function(){
            alert(i);//3
            aBtn[i].style.background='yellow';
         }
 }
}
</script>

思考2:alert(i);//?是多少呢?是undefined。因为aBtn[i].οnclick=function()这个函数会首先预解析,var i=…所以alert(i)为undefined

<script>
window.onload=function(){
 var aBtn=document.getElementsByTagName('input');
        for(var i=0;i<aBtn.length;i++){
         aBtn[i].onclick=function(){
           alert(i);//undefined
           for(var i=0;i<aBtn.length;i++){
              aBtn[i].style.background='yellow';
           }
         }
 }
}
</script>

思考3:把后面那个for循环中的var 去掉。所以alert(i);需要跑到父级去找,此时已经为3了

<script>
window.onload=function(){
 var aBtn=document.getElementsByTagName('input');
        for(var i=0;i<aBtn.length;i++){
         aBtn[i].onclick=function(){
           alert(i);//3
           for(i=0;i<aBtn.length;i++){
              aBtn[i].style.background='yellow';
           }
         }
 }
}
</script>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值