1 javascript

1.1 全局环境下

在全局环境下,this始终指向全局对象(window), 无论是否严格模式;

console.log(this.document === document); // true
// 在浏览器中,全局对象为 window 对象:
console.log(this === window); // true
this.a = 37;
console.log(window.a); // 37

1.2 对象中this

对象内部方法的this指向调用这些方法的对象

  • 函数的定义位置不影响其this指向,this指向只和调用函数的对象有关。
  • 多层嵌套的对象,内部方法的this指向离被调用函数最近的对象window也是对象,其内部对象调用方法的this指向内部对象, 而非window)
var Person = {
	name: "hahah",
    say:function(){
		console.log(this);
    }
}

测试一,此时是Person对象调用:

console.log(Person.name);
console.log(Person.say());

测试结果:
在这里插入图片描述
测试二,此时是window对象调用:

var f = Person.say;
console.log(f());

测试结果:
在这里插入图片描述

1.3 函数中this

普通函数中的this:

  1. this总是代表它的直接调用者(jsthis是执行上下文), 例如 obj.func ,那么func中的this就是obj
  2. 在默认情况(非严格模式下,未使用 use strict),没找到直接调用者,则this指的是 window (约定俗成)
  3. 在严格模式下,没有直接调用者的函数中的thisundefined
  4. 使用call,apply,bind(ES5新增)绑定的,this指的是绑定的对象
  5. 构造函数中的this与被创建的新对象绑定,当构造器返回的默认值是一个this引用的对象时,可以手动设置返回其他的对象,如果返回值不是一个对象,返回this

看调用问题:

var Person = function (){
	this.name = "haha";
	this.say = function(){
		console.log(this);
    }   
}

Person调用:

var p = new Person();
console.log(p.say());
结果----------------
Person {name: "haha", say: ƒ}

window调用:

var p = new Person();
var say = p.say;
console.log(say());
结果----------------
Window {parent: Window, postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ,}

1.4 箭头函数

箭头函数中的this

  1. 箭头函数没有自己的this, 它的this是继承而来; 默认指向在定义它时所处的对象(宿主对象),而不是执行时的对象, 定义它的时候,可能环境是window; 箭头函数可以方便地让我们在 setTimeout ,setInterval中方便的使用this
  2. 箭头函数中,this指向的固定化,并不是因为箭头函数内部有绑定this的机制,实际原因是箭头函数根本没有自己的this,导致内部的this就是外层代码块的this
  3. 箭头函数没有自己的this,它的this是继承而来,默认指向在定义它时所处的对象(宿主对象)。

看例子:
例子一,箭头函数:
此处是箭头函数,此时的this是继承而来,指向在定义它时所处的对象

function Person (){
	this.name = "haha";
	setTimeout(()=>{
		console.log(this);
	},1000);
}
var p = new Person();
结果------------ 一秒后
Person {name: "haha"}

例子二,普通函数:
箭头函数修改为普通函数后,就看谁调用,就指向谁了,由于setInterval跟setTimeout调用的代码运行在与所在函数完全分离的执行环境上,setTimeoutwindow对象的因此指向它

function Person (){
	this.name = "haha";
	setTimeout(function(){
		console.log(this);
	},1000);
}
var p = new Person();
结果------------一秒后
Window {parent: Window, postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ,}

更多this理解可以参考JavaScript面向对象编程:(1)面向对象概述

1.5 例子和总结

看了上面的基本介绍对于this有了基本认知,this的指向在函数定义的时候是确定不了的,只有函数执行的时候才能确定this到底指向谁,实际上this的最终指向的是那个调用它的对象

  1. 如果一个函数中有this,但是它没有被上一级的对象所调用,那么this指向的就是window,这里需要说明的是在js的严格版中this指向的不是window
  2. 如果一个函数中有this,这个函数有被上一级的对象所调用,那么this指向的就是上一级的对象
  3. 如果一个函数中有this,这个函数中包含多个对象,尽管这个函数是被最外层的对象所调用,this指向的也只是它上一级的对象,例子3可以证明,具体讲解需要看下面例子
  4. new关键字可以改变this的指向
  5. 如果函数return返回值是一个对象,那么this指向的就是那个返回的对象,如果返回值不是一个对象那么this还是指向函数的实例,还有一点如果返回null,虽然也是对象,但this还是指向那个函数实例,因为null比较特殊

1.5.1 例一全局对象

function a(){
    var user = "追梦子";
    console.log(this.user); //undefined
    console.log(this); //Window
    }
a();

按照我们上面说的this最终指向的是调用它的对象,这里的函数a实际是被Window对象所点出来的,下面的代码就可以证明

function a(){
    var user = "追梦子";
    console.log(this.user); //undefined
    console.log(this);  //Window
}
window.a();

和上面代码一样吧,其实alert也是window的一个属性,也是window点出来的

1.5.2 例二对象调用

var o = {
    user:"追梦子",
    fn:function(){
        console.log(this.user);  //追梦子    
        }
}
o.fn();

这里的this指向的是对象o,因为调用这个fn是通过o.fn()执行的,那自然指向就是对象o,这里再次强调一点,this的指向在函数创建的时候是决定不了的,在调用的时候才能决定,谁调用的就指向谁,一定要搞清楚这个。

1.5.3 例三嵌套调用

var o = {
    user:"追梦子",
    fn:function(){
        console.log(this.user); //追梦子    
        }
}
window.o.fn();

这段代码和上面的那段代码几乎是一样的,但是这里的this为什么不是指向window,如果按照上面的理论,最终this指向的是调用它的对象,这里先说个而外话,windowjs中的全局对象,我们创建的变量实际上是给window添加属性,所以这里可以用window点o对象

var o = {
    a:10,
    b:{
        a:12,
        fn:function(){
            console.log(this.a); //12        
            }
    }
}
o.b.fn();

这里同样也是对象o点出来的,但是同样this并没有执行它,结合上面的总结看例子就可以了

var o = {
    a:10,
    b:{
        // a:12,
        fn:function(){
            console.log(this.a); //undefined        
            }
    }
}
o.b.fn();

尽管对象b中没有属性a,这个this指向的也是对象b,因为this只会指向它的上一级对象,不管这个对象中有没有this要的东西

1.5.4 例四赋值引用调用

var o = {
    a:10,
    b:{
        a:12,
        fn:function(){
            console.log(this.a); //undefined
            console.log(this); //window        
            }
    }
}
var j = o.b.fn;
j();

这里this指向的是window,是不是有些蒙了
this永远指向的是最后调用它的对象,也就是看它执行的时候是谁调用的,例子4中虽然函数fn是被对象b所引用,但是在将fn赋值给变量j的时候并没有执行所以最终指向的是window,这和例子3是不一样的,例子3是直接执行了fn

1.5.5 例五new构造调用

function Fn(){
    this.user = "追梦子";
}
var a = new Fn();
console.log(a.user); //追梦子

这里之所以对象a可以点出函数Fn里面的user是因为new关键字可以改变this的指向,将这个this指向对象a,为什么说a是对象,因为用了new关键字就是创建一个对象实例,理解这句话可以想想我们的例子3,我们这里用变量a创建了一个Fn的实例(相当于复制了一份Fn对象a里面),此时仅仅只是创建,并没有执行,而调用这个函数Fn的是对象a,那么this指向的自然是对象a,那么为什么对象Fn中会有user,因为已经复制了一份Fn函数对象a中,用了new关键字就等同于复制了一份。

为什么this会指向a?首先new关键字会创建一个空的对象,然后会自动调用一个函数apply方法,将this指向这个空对象,这样的话函数内部的this就会被这个空的对象替代

1.5.6 例六return和this

返回空对象

function fn()  
{  
    this.user = '追梦子';  
    return {};  
}
var a = new fn;  
console.log(a.user); //undefined

返回空函数

function fn()  
{  
    this.user = '追梦子';  
    return function(){};
}
var a = new fn;  
console.log(a.user); //undefined

返回一个值

function fn()  
{  
    this.user = '追梦子';  
    return 1;
}
var a = new fn;  
console.log(a.user); //追梦子

返回undefined

function fn()  
{  
    this.user = '追梦子';  
    return undefined;
}
var a = new fn;  
console.log(a.user); //追梦子

console.log(a); //fn {user: "追梦子"}

返回null

function fn()  
{  
    this.user = '追梦子';  
    return null;
}
var a = new fn;  
console.log(a.user); //追梦子

2 Vuejs

2.1 vue组件中

Vue所有的生命周期钩子方法(如beforeCreatecreatedbeforeMountmountedbeforeUpdateupdatedbeforeDestroy以及destroyed)里使用thisthis指向调用它的Vue实例,即(new Vue

new Vue({
  data: {
    a: 1
  },
  created: function () {
    console.log('a is: ' + this.a)
  }
  methods: {
	plus: function () {
      this.a++
    }
  }
});

vue组件或者实例中,不管是生命周期钩子函数created还是自定义函数plus,他们中的this都是指当前vue实例

2.2 回调函数

methods: {
     searchLocations: function() {
         var address = this.search
         var geocoder = new window.google.maps.Geocoder()
         geocoder.geocode({
             address: address
         }, function(results, status) {
             if (status === window.google.maps.GeocoderStatus.OK) {
                 this.buscarLojas(results[0].geometry.location)
             }
         })
     },
     buscarLojas: function(center) {
         console.log(center)
     }
 }

此时回调函数function(results, status)会重新将this指向匿名对象(类比java匿名类),所以其中的this指代父级组件,执行this.buscarLojas会报错找不到函数

2.3 箭头函数

箭头函数没有自己的this, 它的this是继承而来; 默认指向在定义它时所处的对象(宿主对象),而不是执行时的对象

methods: {
    searchLocations: function () {
      var address = this.search
      var geocoder = new window.google.maps.Geocoder()
      geocoder.geocode({address: address}, (results, status) => {
        if (status === window.google.maps.GeocoderStatus.OK) {
          this.buscarLojas(results[0].geometry.location)
        } else {
          alert(address + ' not found')
        }
      })
    },
    buscarLojas: function (center) {
      console.log(center)
    },
   group1:()=>{
 //ES6的箭头函数写法,箭头函数没有自己的this,它的this事继承来的,指向在定义它时所处的宿主对象,在这里this指向window。
         this.......
   },
}

箭头函数被绑定到父级上下文,因此其中的this会指向父级组件,针对情况三中的问题,将回调函数中的function改成箭头函数,会将this从匿名对象重新指向外部的vue组件

Logo

前往低代码交流专区

更多推荐