js、变量、作用域、作用域链、闭包、this

变量 作用域 作用域链 闭包 this

  • 变量:作用往内存中存储数据
为什么会有作用域?

因为变量需要运行环境,这个环境我们叫做作用域
1:全局作用域是在浏览器或者程序刚开始运行的时候产生的。
2:全局作用域销毁,在关闭浏览器或者关闭程序是。
所以:我们声明的全局变量,都是 window 对象下的属性。
所以:js 中 最大的对象是 window,所有的数据都在 window 下活跃。
所以:全局作用域中最大的对象就是 window 每次改变变量的值,都是给 window 属性重新赋值,
window 属性为声明的变量或者定义的函数名字。

变量与函数名字是如何成为 window 下的属性的?

因为 js 运行经过三个阶段:
1:语言分析
2:预编译
2.1 在全局作用域形成之初,预编译会创建一个 GO 对象,也是全局的
2.2 先将所有声明的变量,提升到作用域最顶端,并赋值为 undefined
2.3 在将所有定义的函数,提升到作用域的顶端,赋值为 函数在堆中的指针
注意:变量声明先提升,然后函数定义在提升。所有的变量用值,都是使用最近的一次赋值
-----> 所以经过预编译后,变量和函数名字就成为了 window 的属性
3:解析执行
每执行一次代码:都会对 window 下的属性进行重新赋值---->也就是数据发生的改变

作用域分类

全局作用域:

  • window 对象下
  • 是最大的作用域
  • 其他的作用域都必须在全局作用域下
    局部作用域:
  • 因为函数体中有声明的变量,函数在执行时,该变量运行需要一个环境,所以就产生了局部作用域
  • 当函数执行完毕时候,看子作用域中是否有需要使用 他声明的变量,如果没有则作用域销毁,变量消失
    (实际是变量赋值为 null),如果用到了,那么就形成了闭包,作用域保存下来
  • 函数的执行环境,是在栈内存中,每次执行都是开辟一个空间,执行完毕消失。
  • 在函数局部作用域中最大的对象叫 AO 对象,AO 对象会随着作用域的存在而存在。
  • 所以 每个作用域中都会有一个最大的对象,局部作用域为 AO 对象,全局为 GO
  • 每个对象中都隐藏 this,默认指向该对象(抽象的对象)。
  • 块级作用域
    1:let 声明的变量 {} 是一个代码块,let 只能在自己的{} 内部进行运行,外部不能访问。
    所以是块级作用域。只看{} 不看函数
    2:块级作用域也遵循作用域链规则,小作用域可以使用大作用域中的变量
    3:for 循环中 let 千万注意:—? 不是一个块(循环多少次就形成多少个块级作用域)
    for (let i = 0; i < 3; i++) {
      setTimeOut(function() {
        console.log(i); // 0 1 2 不是 3 3 3
      }, 1000);
    }
    for (var i = 0; i < 3; i++) {
      // 循环先执行,异步后执行,循环执行完毕 i = 3
      setTimeOut(function() {
        console.log(i); // 3 3 3 i 使用时全局变量 i= 3
      }, 1000);
    }
    
局部作用域 js 是如何编译的

预编译
1:创建 AO 对象 AO:{}
2:将函数体中声明的变量提升到当前作用域的顶端,给 AO 添加属性,赋值为 undefined
3:将函数体中声明的函数提升到作用域的顶端,给 AO 添加属性,属性为函数名字,值是函数的指针
解析执行:
1:每次执行对 AO 中属性进行重新赋值。
2:如果有未经声明直接赋值的变量,那么是给父级作用域中声明的变量进行赋值,所有祖籍域中都没声明,那么给 GO 添加属性

作用域链是什么?

作用域链[scope]

  • 作用域是一层作用域包裹另一层作用域 从而形成作用域链,通过 scope 完成的
  • 作用域链导致了变量的使用规则。
  • 1:在自己的作用域中找,如果没有就去父域中找,直到找到全局域为止
  • 变量查找方式:
  • 1;先看声明,再看赋值,赋值使用就近原则
  • 注意:变量名 = 值 不是全局的,是变量赋值,不是声明
  • 因为在预编译阶段,window 下没有这个属性,只有在解析执行的时候,才给 window 添加该属性,并赋值
    作用域链的存在:是为了可以让小作用域中[使用变量]可以访问到[大作用域]中的变量
var a = 1
function b(){
    console.log(a)
}
b()
// 如果没有作用域链,a is not define
// 因为作用域链,所以 输出 1
作用域名与作用域之间的关系是什么?

1:链式关系,大作用域嵌套小作用域,作用域的层层嵌套形成作用域链

this 与作用域的关系是什么?

因为每个作用域中都有一个最大的对象
this 默认就是存在的,每个作用域中都有,默认指向当前作用域中的对象[抽象的对象]
1:函数中作用域是不稳定的
2:作用域可以赋值给对象
3:对象.函数执行,可以将this 赋值给对象,所以谁调用谁指向谁
列如构造函数中this指向

function creatObj(){
    this.name = arguments[0]
    // return this // 为什么this 指向前面调用函数的对象 
}
// creatObj 创建的一个对象,就是讲构造函数的作用域赋给了新对象,所以this 就指向了这个对象,默认
// return this
var a = new creatObj; // this 指向a对象

闭包

函数内部的变量可以被函数外部方问
原理:通过作用域链完成的
优点:1: 函数外部可以方问函数内部的变量;2: 防止变量被全局变量污染
弊端:每次执行foo() 产生新的闭包.foo函数内部的变量a 不会释放.
注意:每次产生的闭包之间相互独立不受影响

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值