JS、Vue中的this指向 + 使用apply()、call()、bind()方法修改this指向

目录

前言

一、JS中五种情形下的this指向:

1.函数

2.方法

3.构造函数

4.响应函数

5.修改指向时

二、Vue 项目中三种情形下的this指向:

1.被Vue所管理的普通函数

2.不被Vue所管理的函数

3.其他情况

注意:

三、使用apply()、call()、bind()方法修改this指向:

注意:

1. apply()

2. call()

3. bind()


前言

        浏览器在调用函数时,每次都会向函数内部传递一些隐含的参数,this就是其中之一,this的指向是函数执行的上下文对象,而当函数的调用方式不同时,this所指向的这个上下文对象也是不一样的,常见的具体情况如下。


一、JS中五种情形下的this指向:

1.函数

        当以函数的形式调用时,this指向 全局对象window 

function test() {
  console.log(this)
}
//输出内容(全局对象window):Window {window: Window, self: Window, document: document, name: '', location: Location, …}
test()

2.方法

        当以方法的形式调用时,this指向 该方法的调用者

var obj = {
  //当对象的一个属性为函数时,称这个函数为该对象的方法
  test: function() {
    console.log(this)
  }
}
//输出内容(对象obj):{test: ƒ}
obj.test()

3.构造函数

        当以构造函数的形式调用时,this指向 新创建的那个对象

function Test() {
  //使用二元运算符instanceof来验证此时的这个this是Test()类的实例,即该构造函数创建出的新对象
  console.log(this , this instanceof Test)    
}
//输出内容(分别为新对象demo和布尔值true):Test {}    true
var demo = new Test()

4.响应函数

        在事件的响应函数中,this指向 响应函数的绑定者

<button id = 'btn'>
  点我输出this
</button>
var btn = document.getElementById('btn')
//给按钮btn绑定一个点击事件
btn.onclick = function() {
  console.log(this)
}
//点击按钮后的输出内容(按钮btn):<button id = 'btn'> 点我输出this </button>

5.修改指向时

        使用apply()、call()、bind()方法改变this指向时,this的指向就是 方法中所指定的那个对象(详细示例见第三部分)。


二、Vue 项目中三种情形下的this指向:

1.被Vue所管理的普通函数

        被Vue所管理的函数为普通函数时(如 methods computed watch 等配置项中的函数是普通函数的形式时),其this指向 Vue的实例对象vm或组件实例对象vc(以后者为例):

//此为组件HelloWorld.vue内容:
<template>
  <div class="hello">
    <button @click="test()">点我输出this</button>
  </div>
</template>

<script>
export default {
  name: "HelloWorld",
//举methods中的普通函数为例
  methods: {
    test() {
      console.log(this)
    }
  },
};
</script>
//点击按钮后输出内容为(组件实例对象vc):VueComponent {_uid: 5, _isVue: true, __v_skip: true, _scope: EffectScope, $options: {…}, …}

2.不被Vue所管理的函数

        不被Vue所管理的函数若为箭头函数时(当methods、computed、watch等配置项中的定时器回调函数、ajax的回调函数都写为箭头函数的形式时),由于箭头函数的this总是指向词法作用域,即外层调用者,所以此时其this同样指向 Vue的实例对象vm或组件实例对象vc(以后者为例):

//以下为组件HelloWorld.vue的内容:
<template>
  <div class="hello">
    <button @click="test()">点我输出this</button>
  </div>
</template>

<script>
export default {
  name: "HelloWorld",
  methods: {
    test() {
      //开启定时器
      setTimeout(()=> {
        console.log(this);
      }, 200);
    },
  },
};
</script>

<style scoped>
</style>
//点击按钮200ms后输出内容为(组件实例对象vc):VueComponent {_uid: 2, _isVue: true, __v_skip: true, _scope: EffectScope, $options: {…}, …}

3.其他情况

        在 组件的自定义事件(下面的代码以此为例)、全局事件总线消息订阅与发布 中,若其回调函数配置在methods中(见注释写法一),或是其回调函数为箭头函数(见注释写法二),则该回调函数的this指向也是 Vue的实例对象vm或组件实例对象vc(以后者为例):

//以组件的自定义事件为例,以下是App.vue的内容:
<template>
  <div id="app">
    <HelloWorld ref="demo"/>
  </div>
</template>

<script>
import HelloWorld from './components/HelloWorld.vue'

export default {
  name: 'App',
  components: {
    HelloWorld,
  },
  //写法一:将事件回调放在methods中
  methods:{
    test() {
      //输出内容(组件实例对象vc):VueComponent {_uid: 1, _isVue: true, __v_skip: true, _scope: EffectScope, $options: {…}, …}
      console.log(this)
    }
  },
  mounted() {
    this.$refs.demo.$on('showThis',this.test)
  }

  //写法二:将事件回调写在mounted中,使用箭头函数的写法,不写methods中的test()方法
  mounted() {
    //输出内容(组件实例对象vc):VueComponent {_uid: 1, _isVue: true, __v_skip: true, _scope: EffectScope, $options: {…}, …}
    this.$refs.demo.$on('showThis', () => console.log(this))
  }
}
</script>
//以下是HelloWorld.vue的内容:
<template>
  <div class="hello">
    <button @click="emitShowThis()">点我触发showThis事件</button>
  </div>
</template>

<script>
export default {
  name: "HelloWorld",
  methods: {
    emitShowThis() {
      //触发showThis事件
      this.$emit('showThis')
      //解绑showThis事件(若在此时解绑,则点击按钮总共只进行一次输出)
      this.$off('showThis')
    }
  },
};
</script>

注意:

这种情况不多,因为 Vuex 可以替代组件的自定义事件、全局事件总线、消息订阅与发布,如会使用Vuex,则此种情况可以忽略。

另外,将上述三种情况分别反过来,则this的指向将不再为Vue的实例对象vm或组件实例对象vc此时this指向 需要具体分析


三、使用apply()、call()、bind()方法修改this指向:

注意:

值得注意的是,虽然这三种方法都可以改变this的指向,但在使用时也稍有区别:

(1)在调用apply()或call()时,都会直接调用函数执行,但在调用bind()时,就不会调用函数执行,而是会返回一个this指向被修改好的新函数供我们调用。

(2)在传参时,第一个参数就是需要让this去指向的对象,若还有其他参数,在使用apply()时,需要将第二个及以后的参数封装到同一个数组中进行传递;在使用call()时,只需要将其他参数依次在第一个参数之后传递即可;在使用bind()时,第二个及以后的参数需要在新函数中传,传递方式同call()一样,无需封装。

修改示例 具体如下(第一部分中第2种情况下的this指向应为对象obj,现将其修改为window):

1. apply()

        使用apply()方法修改this指向:

var obj = {
  test: function (val) {
    console.log(val, this)
  }
}
//输出内容(100和window):100    Window {window: Window, self: Window, document: document, name: '', location: Location, …}
obj.test.apply(window, [100])

2. call()

        使用call()方法修改this指向:

var obj = {
  test: function (val) {
    console.log(val, this)
  }
}
//输出内容(200和window):200    Window {window: Window, self: Window, document: document, name: '', location: Location, …}
obj.test.call(window, 200)

3. bind()

        使用bind()方法修改this指向:

var obj = {
  test: function (val) {
    console.log(val, this)
  }
}
//输出内容(300和window):300    Window {window: Window, self: Window, document: document, name: '', location: Location, …}
var demo = obj.test.bind(window)
demo(300)

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值