this 和箭头函数

148 阅读4分钟

一、this关键词

this在函数调用时,自动生成的对象,函数的执行方式决定,指向最后调用他的对象。

由此我们可以想到以下几种调用方式:

  1. 普通函数调用,正常情况下指向window,严格模式下为undefined
  2. 为什么会指向window呢 全局变量环境中的变量等同于在window顶级变量定义的

全局中的,在变量环境中的变量等同于在顶级对象(Windows)当中进行了一个挂载。

image.png

fn()函数调用等同于window.fn(),this一定会指向最后调用它的对象。但是这种调用方式是不对的,他会污染window,因此我们就会有严格模式。(use strict),让我们来看下下面的代码:

image.png

函数运行时通过对象函数的方法进行调用method,当我们给它一个赋值时,这个函数仍然可以运行。在JS当中,我们的变量是没有类型的,fn2其实是一个指针,在栈内存中分配了一个空间,指向堆内存函数的地址。

二、构造还是执行函数

函数是如何区分构造还是执行的呢?因为函数是一个对象有着属性 [[constructor]] [[call]]。函数本身有两个方法,当作为普通函数来调用的话就会走call分支来执行函数。

image.png

当使用 new 调用构造函数时,JavaScript引擎会执行以下步骤:

  1. 创建一个新的空对象 {}
  2. 将新对象的原型链指向构造函数的 prototype 属性
  3. 将构造函数的 this 绑定到新创建的对象
  4. 执行构造函数内部代码(为新对象添加属性和方法)
  5. 如果构造函数没有显式返回对象,则返回这个新对象

construct 过程本质上完成了对象的初始化和原型关联,使新对象能够继承构造函数原型上的属性和方法。

image.png

普通函数作为method,还有引用函数,构造函数来运行,让我们来看下最后的一种方法!!!

三、事件的回调函数

this指向事件发生的对象,最后谁调用谁负责,还是由它的调用对象来决定的。指向事件发生的对象,this由函数的调用方式决定的。

    <button id="btn">点击</button>
    <script>
      const btn = document.getElementById('btn');
      btn.addEventListener('click',function(){
        console.log(this); // <button id="btn">点击</button>
      })

这里的运行是会报错的,this指向的是window,当我们修改 var _this=this时就可以解决该问题。 这里叫做this的丢失,作用域链解决这个问题;

image.png

四、 call apply bind (霸道一些)

看下面代码,为什么函数最后的运行方式是undefined呢?

image.png

setTimeout函数运行时是异步的,执行的函数是匿名函数,调用方式是普通函数,我们可以发现调用this.func1()的是匿名函数。这时候我们会发现会报错,在严格模式下则为undefined,因为这时候this指向的是window,而全局没有func1()这个方法。

image.png

如何将setTimeout函数运行时内部的this指向a呢?来看下面的代码,当this丢失的时候,我们可以通过作用域链来使用外层的this.

image.png

能够指定call的方法,接受一个参数,这个参数将是能够指定当这个函数调用的时候它内部的this的指向被强制指向为a,也完成了将内部的this指向a。函数对象的原型链上有一个 call, apply 等方法 指定 this 指向 为第一个参数.

image.png

image.png

我们可以看下b.bind如何执行,b.apply(a,[1,2]),bind生成的函数跟call和apply有个共同点,当它在运行时,它的内部的this是被指定的。

区别与用法

image.png

  1. call/apply :调用即执行,参数格式不同,用完即焚
  2. bind :绑定不执行,返回新函数,this被永久锁定
  3. 优先级 :bind > call/apply,绑定后无法被再次修改this 记住 :想立即执行用call/apply,想延迟执行用bind!

五、 封装函数

查找元素,设定点击事件,这样写的话下次继续使用的话就会很麻烦,我们可以将函数封装一下,一个方法一个函数,方便复用。

image.png

当我们点击变色按钮时出现下列报错情况,为什么会出现这种情况呢?

image.png

this丢失问题,下面的this指向this.element,当我们把function()函数换成箭头函数就可以实现,那有没有其它方法呢。

image.png

我们可以看下下述代码,不用call和apply的原因是因为call和apply函数会立刻运行。只要一个函数调用了call和apply之后就会立马运行。

Button.prototype.bindEvent = function(){
  // this 丢失问题  // this Button
  this.element.addEventListener('click',function(){
    // this => this.element
    this.element.style.backgroundColor = 'red';
  }.bind(this))
}

我们可以看到这里的this指向this.element,因为作为事件的处理函数被调用,处理函数是对下述函数的引用,不再是对象上的一个方法,而是函数。这个函数我们要让它内部的this要指向它的实例。

image.png

Button.prototype.bindEvent = function(){
  // this 丢失问题  // this Button
  this.element.addEventListener('click',this.setBgColor.bind(this))
}