this代表当前this直属函数的所处的对象

  1. 此时的this表示people
  2. let people = {
  3. name: 'dong',
  4. sayName: function() {
  5. console.log(this.name)
  6. }
  7. }
  8. // dong
  1. const app = {
  2. init() {
  3. this.$btn = document.querySelector('button')
  4. this.bind()
  5. },
  6. bind() {
  7. this.$btn.onclick = function() {
  8. console.log(this)
  9. this.getData() //这样写对吗,如果不对该如何修改?
  10. }
  11. },
  12. getData() {
  13. console.log('get data...')
  14. }
  15. }
  16. app.init()

init方法里的this指的是app

bind方法里,根据定义,第8,9行的this指的不是app,而是 $btn元素对象,$btn元素对象没有getData方法所以会报错

修改方法 方法一:先把this对象复制到self

  1. bind() {
  2. let self = this
  3. this.$btn.onclick = function() {
  4. console.log(this) // 这个this 还是 btn 对象
  5. self.getData() //self 代表外面的this,也就是app
  6. }
  7. },

方法二:使用箭头函数 () =>{}
箭头函数没有this,所以此时this的直属函数是bind

  1. bind() {
  2. this.$btn.onclick = () => {
  3. console.log(this) // 在确定this直属的函数时,不考虑箭头函数
  4. this.getData() // 所以当前this直属的函数是bind
  5. }
  6. },

案例

  1. let name = '中国'
  2. let people = {
  3. name: '郑州',
  4. sayName() {
  5. console.log(this.name)
  6. }
  7. }
  8. let sayAgain = people.sayName
  9. function sayName(){
  10. console.log(this.name)
  11. }
  12. people.sayName()
  13. sayAgain()
  14. sayName()

执行people.sayName()会输出郑州,因为他的this的直属函数是sayName,所属对象是people

执行sayAgain(),就会调用执行 people.sayName(),调用了sayAgain才执行函数,所以this的直属函数是sayAgain,sayAgain所属的对象在非严格模式下我们普遍认为是window ,所以this指向window, 因为let不会在全局声明时(在最顶部的范围)创建window 对象的属性。所以name变量并不是window的属性,所以输出的是空的,如果使用var定义name变量那么就会打印出“中国”

执行sayName()时,此时this的直属函数是sayName(),它的所属对象就是window,所以this就是window

数组的this

  1. let arr = []
  2. for(let i=0; i<3; i++){
  3. arr[i] = function() { console.log(this) }
  4. }
  5. arr[0]()
  6. let fn = arr[0]
  7. fn()

数组也是一种对象,相当于{ 0:值,1:值}

for循环执行完后数组里面相当于存了三个函数 [ƒ, ƒ, ƒ]
执行 arr[0]() 时,this的直属函数就是arr[0],所属对象就是数组,所以会打印出数组

执行 fn() , 此时this的所属对象就是fn(),而fn的所属对象是window,所以打印处window对象

定时器的this

  1. let people = {
  2. name: 'dong',
  3. sayName() {
  4. setTimeout(function(){
  5. console.log(this.name)
  6. }, 0)
  7. }
  8. }
  9. people.sayName()

此时this的直属函数是function,而它的所属对象是window,所以this指向window,window并没有name属性,所以打印出undefined

箭头函数的this

箭头函数的this会被我们忽略掉,找它上一级的函数

箭头函数没有this或者理解成箭头函数的this是箭头函数直属的函数

  1. let people = {
  2. name: 'dong',
  3. sayName() {
  4. setTimeout(() => {
  5. console.log(this.name)
  6. }, 0)
  7. }
  8. }
  9. people.sayName()

因为this直属的函数是箭头函数,箭头函数的this是 箭头函数直属的函数也就是sayName(),而sayName()属于people,所以this代表people,会打印出 dong

构造函数的this

  1. function Wife(name) {
  2. this.name = name
  3. }
  4. Wife.prototype.showSkill = function() {
  5. console.log('我是' + this.name + ', 我的技能是唱歌、跳舞、打游戏')
  6. }

一个直男幻想着:如果我以后有个女神老婆,她的技能最好是唱歌、跳舞、打游戏。上面代码里的this(出现在构造函数内和原型的方法内)就代表幻想的那个未来的那个“她”。

那么我现在开始创建,创建的是谁,这个this就是谁
我创建这个老婆是刘亦菲,那么这个this就是刘亦菲

  1. let wife = new Wife('刘亦菲')
  2. wife.showSkill()

我创建这个老婆是佟丽娅,那么这个this就是佟丽娅

  1. let wife = new Wife('佟丽娅')
  2. wife.showSkill()

只有new之后,真正的 wife 才创建,之前幻想时对 她(this) 的操作才真正开始实施。对this操作就是对wife的操作。

更改this指向的对象

this默认是当前this直属的函数所处的对象,可以使用 call/apply/bind,方法传入第一个参数就是指向的对象

  1. let obj = {
  2. fn(a, b) {
  3. console.log(this)
  4. }
  5. }
  6. obj.fn(1, 2) //打印出obj对象
  7. //等价于
  8. obj.fn.call(obj, 1, 2) // 所以 this 是 obj
  9. obj.fn.apply(obj, [1, 2])
  10. obj.fn.bind(obj)(1, 2)

call/apply/bind里面第一个参数传什么,函数里面的this就是什么。

  1. let obj = {name: 'dong'}
  2. function sayName(){
  3. console.log(this.name)
  4. }
  5. let fn = sayName.bind(obj)
  6. fn() // 输出: 'dong'

不使用bind时,this所属的对象是window,使用bind并将obj对象传入,则this就是obj

复杂案例

  1. let app = {
  2. container: document.querySelector('body'),
  3. init: function(){
  4. //点击的时候会执行 sayHello,sayHello 里面的 this 代表 body 对象
  5. this.container.addEventListener('click', this.sayHello)
  6. //点击的时候会执行 sayHello,sayHello 里面的 this 代表 app 对象
  7. this.container.addEventListener('click', this.sayHello.bind(this))
  8. },
  9. sayHello: function(){
  10. console.log(this)
  11. }
  12. }
  13. app.init()

init函数里的两个this指的是app

点击调用sayHello函数,此时sayHello里this直属的函数是click,click的所属对象就是DOM对象container也就是body

使用bind传参,传入的this就是当前对象app,所以此时再调用sayHello函数它里面的this就是app

调用时使用call来判断this

没有对象调用时,那么call传入的参数就是空,默认指向window;

有对象调用时传入的参数就是调用的对象,那么this就是此对象
第一题
image.png
使用call方法转变后
image.png
外面的this;
里面的this;
里面的this;
外面的this;

第二题:打印出10和2
image.png

总结

当看到this时,想知道它是什么,就需要看

  • this的直属函数是谁,忽略箭头函数
  • 直属函数是哪个对象上的方法
  • 有没有使用过call、apply、bind来修改this