作用域和作用域链

发布时间:2022-07-01 发布网站:脚本宝典
脚本宝典收集整理的这篇文章主要介绍了作用域和作用域链脚本宝典觉得挺不错的,现在分享给大家,也给大家做个参考。

什么是作用域

作用域决定了代码区块中变量和其他资的可见性,**作用域就是一个独立的独立的地盘,让变量不外泄.暴露出去,作用域最大的用处就是隔离变量,不同作用域下变量名不会冲突  

作用域可以分为

1.全局作用域,

2.私有作用域

3.es6块级作用域

 全局作用域

当打开页面的时候,会提供一个供js代码执行的环境,全局作用域,会默认提供一个最大的window对象。 【全局变量】F1a;在全局作用域中声明的变量就是全局变量,其中下面的a 和fn 就是全局变量 【全局变量和window关系】 在全局作用域中声明的变量:VAR、function(除去es6的),相当于给window上添加了属性,属性名就是变量名,属性值就是变量值  调用window 下的方法时,可以省去window不写:  

window.alert("1");
alert("1");

window.Number("1");
Number("1");


var a=3; // a是全局变量
function fn(){ // fn 是全局变量
      var num=3;
      function f1(){
      }
}

console.LOG(window.a);
console.log(window.fn);

所有未定义直接赋值的变量自动声明为拥有全局变量

所有window对象的属性拥有全局作用域

所有window对象拥有全局作用域

全局作用域的弊端:如果我们写了很多行代码,变量定义没有用函数包括,那么他们就全部在全局作用域中,这样会污染全局命名空间容易引起命名冲突

函数作用域(私有作用域)

【私有变量】:

  • 形参
  • 在私有作用域中声明的变量就是私有变量。

在私有作用域外面,去访问私有变量的话,是访问不到的,但是在私有作用域里面可以访问到外面的变量。

        var a = 66;

        function fn() {
            var x = 1;
            var y = 3;
            console.log(a);//66
            return x + y;
        }
        console.log(x);// x is not defined

        fn();

块语句(大括号{}中间的语句)如SwITch和if条件语句或for和while循环语句,不像函数它们不会创建新的作用域,在块语句级作用域中定义的变量将保留在他们已经存在的作用域中

es6块级作用域

先来看一下es6中的let

let不存在变量提升

console.log(a);//Uncaught ReferenceError: a is not defined
let a=2;

阻断了和window的关系

let a=2;
console.log(window.a);// undefined

不能重复声明

es6中没有变量提升,但是有一个自我检测的一个机制,在代码自上而下执行前,会先进行检测,看是否有重复声明的变量,如果有的话,就先报错。

let a=2;
console.log(a);
var a=3; // 不能进行重复的声明:Uncaught SyntaxError: Identifier 'a' has already been declared
console.log(3);

暂时性死区

ES6明确规定,如果区块中存在let和const命令,这个区块对这些命令声明的变量,从一开始就形成了封闭作用域。凡是在声明之前就使用这些变量,就会报错。在代码块内,使用let命令声明变量之前,该变量都是不可用的。这在语法上,称为“暂时性死区”(temporal dead zone,简称 TDZ)。

我们来看块级作用域

块级作用域可以通过新增命令let和const声明,所声明的变量在指定块的作用域外无法访问,块级作用域在如下情况被创建

1.在一个函数内部

2.在一个代码块(由一对花括号包裹)内部

我们来看循环中的块级作用域 更好的了解一下块级作用域

   var a = [];
        for (var i = 0; i < 10; i++) {
            a[i] = function () {
                console.log(i);
            }
        }
        a[6]();//10

上面代码中,变量i是var声明的,在全局范围内有效,全局中只有有一个变量i每次循环i的值都会发生变化,而循环内的i指向的是全局的i,也就是说所有数组a的成员里面的i指向的都是同一个i导致运行时输出的结果是最后一轮i的值 也就是10

再来看用let声明的 声明的变量仅在块级作用域内部有效 最后输出的结果是6

   var a = [];
        for (let i = 0; i < 10; i++) {
            a[i] = function () {
                console.log(i);
            }
        }
        a[6]();// 6

变量i是let声明的,当前的i只在本轮循环有效,所以每次循环你的i其实都是一个新的变量所以最后输出的结果是6

思考:如果每一轮循环的变量i都是重复声明的那它怎么知道上一轮循环的值,从而计算出本轮循环的值?

这是因为js引擎内部会记住上一轮循环的值 ,初始化本轮的变量i时 就在上一轮循环的基础上进行计算

什么是作用域链

在私有作用域中,如果没有定义这个私有变量,就会向上一级作用域进行查找,如果都没有,继续进行查找,直到查找到window为止。如果是赋值,声明的时候用了var、function 就是给GO添加(也是给window)添加,不带任何关键字的,相当于省了window,也是给Go添加,如果声明的时候用了let、const 直接给VO添加。

上级作用域:

当前函数执行,形成一个私有作用域A,这个A的上级作用域是谁,跟它在哪执行无关,跟它在哪定义(创建)有关系,在哪创建,它的上级作用域就是谁

简而言之:上级作用域和函数在哪执行无关,和函数在哪定义有关

练习题

console.log(a,b);// undefined undefined
var a=12,
b=12;
function fn(){
    console.log(a,b);// undefined 12
    var a=b=13;
    console.log(a,b);// 13 13
}
fn();
console.log(a,b);// 12 13


 [解析] 

代码自上而下执行之前会把var 和function进行变量和提升 var只声明不定义function声明和定义一起完成 ,

代码自上而下执行 此时console.log(a,b) 都是undefined,提升阶段函数fn已经不在执行直接跳过

在调用fn fn执行 会形成私有作用域普通函数执行

普通函数执行

  • 会形成全新的私有上下文
  • 初始化自己的作用域链{自己的上下文,上级上下文'}
  • 初始化this
  • 初始化arguments
  • 形参赋值
  • 变量提升
  • 代码执行
  • 默认返回undefined

此时函数内部的a提升到自己作用域的顶部还是只声明不定义   console.log(a,b)a 是undefined b会根据作用域链找到全局 b为12

   var a=b=13; 此时b不带var不是私有变量会向上一级作用域进行查找 如果还没有找到,一直继续向上查找直到找到window这种机制叫做作用域链查找,   console.log(a,b)此时a是私有13,b不是私有变量,并将全局的b修改为13

  console.log(a,b) 打印的是全局的ab 现在是 a12 b13

作用域和作用域链

-------------------------------------完结-------------------------------------------------- -------------------------接收大佬们的批改和指点,欢迎留言-------------------------------------

脚本宝典总结

以上是脚本宝典为你收集整理的作用域和作用域链全部内容,希望文章能够帮你解决作用域和作用域链所遇到的问题。

如果觉得脚本宝典网站内容还不错,欢迎将脚本宝典推荐好友。

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。