欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

javascript--12---作用域

程序员文章站 2022-07-15 10:40:29
...

作用域

  1. 什么是作用域
  • 作用: 对代码的一个读写操作
  • 域:空间 范围 js能实现的一个范围
<script>
    console.log(a);
    var a =1;
  
</script>

结果是undefined
没有声明为什么会报undefined? 首先预解析 找到a 为undefined 执行代码 =改变变量的值 但是console在等号之前 所以结果是 undefined

<script>
    a =1;
    console.log(a);
</script>

为什么没有声明却能打印出1?

  • 如果 在script没有声明 直接赋值 也能行
<script>
    console.log(a);
    a =1;
</script>

直接报错
为啥是报错? 预解析 没找到a 没有var 在console.log之前 既没有声明 也没有赋值 所以报错 后面的a=1相当于没有

<script>
   var a=1;
   console.log(window.a);
</script>

结果是1 window是script标签中最大的一个对象

  • 平时在script 中var的时候 其实是在最大的window上加了一个属性
<script>
   a=1;
   console.log(window.a);
</script>

结果是1

  • 没有var也会自动在window上加一个属性 这是系统在找不到声明的时候 自动加的

解释器

js是一种直译式脚本语言

  1. 解释器:在浏览器内核中有一个解释器 看到script标签 就直接撸起袖子干 没有长期的准备
  2. 解释器在读取js代码的时候 也至少分为两步
  • 找一些东西 根据关键字 去查找 var(变量声明) function(函数声明) 参数
    找到变量声明之后 不去读取赋值 而是直接给一个undefined值

    找到函数声明之后不会执行函数  而是把函数的内容当作一块直接存起来
      比如  a:function(){}
  • 解释代码 先找到我们的 预解析找到的变量 如果有能改变变量值的运算:+ — ++ -- */% 修改了这个先找到的undefined/function(){}

<script>
   alert(a);//结果是function a(){alert(3)}
   var a=1;
   alert(a);//结果是1
   function a() {
       alert(2);
   }
   alert(a);//结果是1
   var a=3;
   alert(a);//结果是3
   function a() {
       alert(3);
   }
   alert(a);//结果是3
   a();//报错
</script>
  1. 预解析
  • a :undefined 如果预解析过程中 函数名和变量重名了 函数会把变量无情覆盖
  • a :function{alert(2)}
  • 如果预解析中 有重名函数 后者会把前者覆盖
  • a :function{alert(3)}
  1. 执行阶段
  • 第一个alert 结果是打印函数体function{alert(3)}
  • 修改a=1,第二个alert 结果是打印1
  • function只在预解析会用到 跳过function 第三个alert 结果是打印1
  • 修改a=3,第四个alert 结果是打印3
  • 跳过function 第五个alert 结果是打印3
  • a=3 3();是啥哦 会报错

全局作用域 和 局部作用域

全局作用域

  1. 最大的作用域是 script标签之间 全局中最大的对象是 window window是最大的作用域 但是script是分别解释的 代码自上而下执行 script全部解读完之后 window还是最大的对象 在引入代码的时候一定要注意引入顺序 因为script是分别解释的
<script>
  alert(a);
</script>
<script>
    var a =1;
</script>

结果会报错 代码自上而下执行 没有解析下面的var a=1;

<script>
   var a =1;
</script>
<script>
  alert(a);
</script>

结果是1; 会把a=1存起来 执行到下一个script 会在小仓库里找a

局部作用域

  1. 函数内部也是一个空间 函数构建的空间 可以被看作一个局部作用域
  2. 如果局部作用域的预解析的空间 没有找到 那么我的代码执行 会从上一级作用域寻找 上一级作用域不能在下一级作用域寻找
  3. 预解析的空间 :AO ----活动对象
<script>
  var a =1;
  function fn1() {
      alert(a);
      var a =2;
  }
  fn1();
  alert(a);
</script>

第一个结果是 undefined 第二个结果是 1

  1. 预解析 AO分析
  • a:undefined fn1{}
  1. 代码执行 a=1
  • fn1执行 :进入函数内部 1预解析 a:undefined 2 执行 alert(a) a=2
  • alert(a) 所以结果是先 undefined 后1
<script>
  var a =1;
  function fn1() {
      alert(a);
  }
  fn1();
  alert(a);
</script>

结果是1 1

  1. 预解析
  • a:undefined fn1{}
  1. 代码执行 a=1
  • fn1执行 :进入函数内部 1预解析 预解析是空 2 执行 alert(a) 跳出函数在全局中寻找a a=1 所以结果是1
  • alert(a) 所以结果是先 1 后1

参数

  1. 形参 相当于隐式声明 在AO上为undefined
  2. 实参 会在AO分析时候 给形参一个初始值
<script>
  var a =1;
  function fn1(a) {
      alert(a);
      a =2;
  }
  fn1();
  alert(a);
</script>
  1. 预解析
  • a:undefined fn1{}
  1. 代码执行 a=1
  • fn1执行 :进入函数内部 1预解析 形参相当于声明变量a:undefined 2 执行 alert(a)所以结果是undefined 之后赋值a=2;
  • alert(a) 所以结果是先 undefined 后1
<script>
  var a =1;
  function fn1(a) {
      alert(a);
      a =2;
      alert(a);
  }
  fn1(a);
  alert(a);
</script>
  1. 预解析
  • a:undefined fn1{}
  1. 代码执行 a=1
  • fn1执行 :进入函数内部 1预解析 实参传值 a=1 2 执行 alert(a)所以结果是1 之后赋值a=2;
  • alert(a) 所以结果是先 1 后2 再 1
<script>
   var a =1;
   function f1() {
    alert(a);
    a=2;
   }
   f1();
   alert(a);
</script>

结果是 1 2

<script>
  var age =99;
  function t(age) {
      alert(age);
  }
  t(5);
  t();
</script>
  1. 预解析
  • age:undefined t:function{}
  1. 代码执行 age=99
  • t(5)执行 :进入函数内部 1预解析 实参传值 age=5 2 执行 alert(age)所以结果是5
  • t()执行 进入函数 1 预解析 形参相当于声明变量a:undefined alert(age) 所以结果是先5 后undefined
<script>
  function t2(green) {
      alert(green);
      function green() {

      }
      green="hello";
      alert(green);
  }
  t2(null);
  1. 预解析
  • green:null 进入函数内部 有一个函数声明 会覆盖 green=function green() {}
  1. 代码执行 alert(green) 结果是 function
  • green:hello
  • alert(green) 结果是hello 所以 第一个是函数体 第二个是hello
<script>
  function a(b) {
      alert(b);
      function b() {
          alert(b);
      }
      b();
  }
  a(1);
</script>
  1. 预解析
  • b=1 进入函数内部 有一个函数声明 会覆盖 b=function b(){}
  1. 代码执行 alert(b) 结果是 function
  • b() 执行 进入b(){}内部 并没有 var b 跳出当前函数 找到b为function 所以alert(b) 是函数本身 结果两个都是函数本身
<script>
  function a(b) {
      alert(b);
      b=function(){
          alert(b);
      }
      b();
  }
  a(1);
</script>
  1. 预解析
  • b=1 进入函数内部 没有函数声明 变量声明
  • 代码执行 alert(b) 结果是1
  • 赋值b=function(){}
  1. b()执行 进入函数体内部 没有var b 跳出 b=function 结果是function 所以第一个是1 第二个是函数本身

作用域分析

  1. 先看看有没有参数 实参会把形参初始化 如果只有形参 那么形参为undefined
  2. 再看看有没有变量声明 函数会把同名变量覆盖 包括实参

jquery部分代码

  1. 传window是为了性能
  2. 不穿undefined 是为了函数内部不被污染
<script>
  (function (window,undefined) {
      function(){
          function(){
              function(){
                  window.document.getElementById()
              }
          }
      }
  })(window);
</script>

如果函数内部没有 window 那么document.getElementById()要执行 会跳出这个函数 当层数太多 性能就会很低 所以会实参会传一个window到函数内部 形参undefined 初始值就是undefined 不用实参传 再低版本的ie中 undefined可以被赋值 如果在函数外部 定义undefined=1 实参传undefined 那么函数内部undefined 就会被污染为1 如果函数内部做判断 if(a==undefined)就不可以

作用域链

内层作用域在寻找变量时候未找到 会沿着作用域上的AO 向上寻找 直到全局

相关标签: 作用域