前端基础不能忘之JS(一)

633 阅读6分钟

作用域链/闭包/变量提升

作用域链

  • 每个执行上下文的变量环境中,都包含了一个引用outer,指向外部的执行上下文。当一段代码使用了一个变量时,js引擎会先在当前的执行上下文中查找,如果没有找到,js引擎继续在outer所指向的js引擎中查找,这个查找的链条就叫是作用域链

闭包

  • 定义
    • 根据词法作用域的规则,内部函数总是可以访问外部函数的中声明的变量,当通过调用一个外部函数返回一个内部函数后,即使该外部函数已经执行结束了,但是内部函数引用外部函数的变量仍然保存在内存中,这些变量的集合就是闭包
    • 闭包的外部作用域是在其定义的时候已决定,而不是执行的时候。
    • 变量的生命周期取决于闭包的生命周期。被闭包引用的外部作用域中的变量将一直存活直到闭包函数被销毁。如果一个变量被多个闭包所引用,那么直到所有的闭包被垃圾回收后,该变量才会被销毁。
  • 使用场景
    • 在异步任务例如 timer 定时器,事件处理,Ajax 请求中被作为回调
    • 被外部函数作为返回结果返回,或者返回结果对象中引用该内部函数
    • 维护一些私有变量

一段JavaScript代码是如何执行的

  • JavaScript执行机制是先编译,再执行
  1. 所有在编译阶段 会生成执行上下文(变量环境和词法环境)和可执行代码
  2. 在执行上下文中会有一个变量环境对象
  3. 函数提升要比变量提升的优先级要高一些,且不会被变量声明覆盖,但是会被变量赋值之后覆盖。

变量提升

  • JavaScript 代码执行过程中,需要先做变量提升。而之所以需要实现变量提升,是因为 JavaScript 代码在执行之前需要先编译。在编译阶段,变量和函数会被存放到变量环境中,变量的默认值会被设置为 undefined;在代码执行阶段,JavaScript 引擎会从变量环境中去查找自定义的变量和函数。如果在编译阶段,存在两个相同的函数,那么最终存放在变量环境中的是最后定义的那个,这是因为后定义的会覆盖掉之前定义的。

原型/原型链

原型

  • 定义: JS 原型是指为其它对象提供共享属性访问对象。在创建对象时,每个对象都包含一个隐式引用指向它的原型对象或者 null。
    • 每个函数function都有一个prototype,即显式原型
    • 每个实例对象都有一个__proto__,可称为隐式原型
    • 对象的隐式原型的值为其对应构造函数的显式原型的值

原型链

  • 定义:原型链是由原型对象组成,每个对象都有 __proto__ 属性,指向创建该对象的构造函数的原型,__proto__ 将对象连接起来组成原型链,是一个用来实现继承和共享属性的有限的对象链

    • 属性查找机制:当查找对象的属性时,如果实例对象自身不存在该属性,则沿着原型链往上一级查找,找到则输出,不存在时,再继续沿着原型链往上一级查找,直至最顶级的原型对象 Object.prototype,如果还是没有找到,则输出 undefined
    • 属性修改机制:只会修改实例对象本身的属性,如果不存在,则进行添加改属性,如果需要修改原型的属性时,则可以用 obj.prototype.x = 1,但是这样会造成所有继承与该对象的实例属性的改变
  • 如何利用原型实现继承

    • 一种是通过 Object.create (proto[, propertiesObject])或者 Object.setPrototypeOf (obj:要设置其原型的对象, prototype:该对象的新原型)显式继承另一个对象,将它设置为原型。
    • 另一种是通过 constructor 构造函数,在使用 new 关键字实例化时,会自动继承 constructorprototype 对象,作为实例的原型。
  • 继承的几种方式

this/call/apply/bind/箭头函数

this

  • 定义

    • this 关键字执行为当前执行环境的 ThisBinding
    • this的指向是调用时决定的,而不是创建时决定的
  • 调用位置

    • 全局上下文(非严格模式下)

      • this等价于window对象
      • var === this. === winodw.
    • 函数上下文

      • 在函数内部,this的值取决于函数被调用的方式。

      1. 直接调用
        this指向全局变量。

      2. call()、apply()
        this指向绑定的对象上。

      3. bind()
        this将永久地被绑定到了bind的第一个参数。

      4. 箭头函数

        • 箭头函数适合与this无关的回调,定时器,数组的回调
        • 没有自己的thisargumentssupernew.target
        • 它的所谓的this是捕获其所在上下文的 this 值,作为自己的this值,并且由于没有属于自己的this
        • this是静态的,this始终指向函数声明时所在作用域的this的值,不能用apply和call改变this指向
        • 箭头函数表达式更适用于那些本来需要匿名函数的地方,并且它不能用作构造函数
        • 对于methodswatch中的方法官方不推荐使用箭头函数,理由是:“箭头函数绑定了父级作用域的上下文,所以 this 将不会按照期望指向 Vue 实例,this.a 将是 undefined”。
      5. 作为对象的一个方法 this指向调用函数的对象

      6. 严格模式下的函数调用下, this指向undefined

      7. 作为一个构造函数

        this被绑定到正在构造的新对象

      8. 作为一个DOM事件处理函数

        this指向触发事件的元素,也就是始事件处理程序所绑定到的DOM节点

      9. HTML标签内联事件处理函数

        this指向所在的DOM元素

      10. jQuery的this

        在许多情况下JQuery的this都指向DOM元素节点。

      11. map的第二个参数,改变this的指向

call/apply/bind有什么区别

  • call:改变this指向,第二个参数为参数列表,函数执行
  • apply:改变this指向,第二个参数为数组,函数执行
  • bind:改变this指向,第二个参数为参数列表返回函数

如何实现call、apply、bind

  • call
  • apply
  • bind