作用域

变量声明提升

变量提升的表现是,无论我们在函数中何处位置声明的变量,好像都被提升到了函数的首部,我们可以在变量声明前访问到而不会报错。

造成变量声明提升的本质原因是 js 引擎在代码执行前有一个解析的过程创建了执行上下文初始化了一些代码执行时需要用到的对象。当我们访问一个变量时,我们会到当前执行上下文中作用域链中去查找,而作用域链的首端指向的是当前执行上下文的变量对象,这个变量对象是执行上下文的一个属性,它包含了函数的形参、所有的函数和变量声明,这个对象的是在代码解析时候创建的。这就是会出现变量声明提升的根本原因

详细资料可以参考: 《JavaScript 深入理解之变量对象》

变量对象里的函数不会被值覆盖

  1. var foo = 10;
  2. function foo(){
  3. console.log("foo");
  4. }
  5. console.log(foo)
  6. // 10
  1. function foo(){
  2. console.log("foo");
  3. }
  4. var foo = 10;
  5. console.log(foo);
  6. // 10
  1. console.log(foo);
  2. function foo(){
  3. console.log("foo")
  4. }
  5. console.log(foo);
  6. var foo = 1;
  7. console.log(foo);
  8. //ƒ foo(){
  9. // console.log("foo")
  10. //}
  11. //ƒ foo(){
  12. // console.log("foo")
  13. //}
  14. // 1

JavaScript深入之执行上下文

作用域链

  • 作用域链的作用是保证对执行环境有权访问的所有变量和函数的有序访问,通过作用域链,我们可以访问到外层环境的变量和函数
  • 作用域链的本质上是一个指向变量对象的指针列表变量对象是一个包含执行环境中**所有变量和函数**的对象。
  • 作用域链**的前端始终都是当前执行上下文的变量对象。全局执行上下文的变量对象(也就是全局对象)始终是作用域链的最后一个**对象。
  • 当我们查找一个变量时,如果当前执行环境中没有找到,我们可以沿着作用域链向后查找

this对象

this 是执行上下文中的一个属性,它指向最后一次调用这个方法的对象。在实际开发中,this 的指向可以通过四种调用模式来判断。

  1. 函数调用模式,当一个函数不是一个对象的属性时,直接作为函数来调用时,this 指向全局对象。
  2. 方法调用模式,如果一个函数作为一个对象的方法来调用时,this 指向这个对象。
  3. 构造器调用模式,如果一个函数用 new 调用时,函数执行前会新创建一个对象,this 指向这个新创建的对象。
  4. apply 、 call 和 bind 调用模式,这三个方法都可以显示的指定调用函数的 this 指向。其中 apply 方法接收两个参数:一个是 this 绑定的对象,一个是参数数组。call 方法接收的参数,第一个是 this 绑定的对象,后面的其余参数是传入函数执行的参数。也就是说,在使用 call() 方法时,传递给函数的参数必须逐个列举出来。bind 方法通过传入一个对象,返回一个 this 绑定了传入对象的新函数。这个函数的 this 指向除了使用 new 时会被改变,其他情况下都不会改变。

优先级 构造器调用 -> apply;call;bind-> 方法 ->函数

  1. window.text = "windowText";
  2. var a = {
  3. text:"a.Text",
  4. say:function (){
  5. console.log(this.text)
  6. },
  7. say2:()=>{
  8. console.log(this.text)
  9. }
  10. }
  11. a.say() // "a.Text"
  12. a.say2() // windowText
  13. var d = a.say
  14. d() // windowText
  15. var s = a.say2
  16. s() // windowText

《JavaScript 深入理解之 this 详解》

闭包

闭包有权访问另一个函数作用域中变量的函数,创建闭包的最常见的方式就是在一个函数内创建另一个函数,创建的函数可以访问到当前函数的局部变量。

闭包有两个常用的用途

  • 闭包的第一个用途是使我们在函数外部能够访问到函数内部的变量。通过使用闭包,我们可以通过在外部调用闭包函数,从而在外部访问到函数内部的变量,可以使用这种方法来创建私有变量
  • 函数的另一个用途是使已经运行结束的函数上下文中的变量对象继续留在**内存中**,因为闭包函数保留了这个变量对象的引用,所以这个变量对象不会被回收。

其实闭包的本质就是作用域链的一个特殊的应用,只要了解了作用域链的创建过程,就能够理解闭包的实现原理。

详细资料可以参考: 《JavaScript 深入理解之闭包》

相关文章