神奇的this

753 阅读3分钟

前言

在代码之中,我们经常会遇到this,一般都会说它指的是函数上下文,本文从各个场景说明this含义。

可能指向有哪些呢?

全局对象

在大环境中,this指向全局对象,比如浏览器环境的this是window对象,vue组件中的this指向的是vue对象。(不考虑node环境) 备注:如果你在浏览器环境中的函数使用this,然后直接调用函数而不是实例化,此时的this是window而不是函数(非严格模式下)。

function fn1(){
  console.log(this);
}
fn1();//window

var app=new Vue(){
     data:{
    }
     methods:[
        test:function(){
             console.log(this);//vue  
   }
  ]
}; 

作为对象的属性

说明,对象中的属性函数中的this指向的是对象本身,但是当你把它的函数部分当做函数的时候,this又会指向浏览器的window(浏览器环境下);

// 对象属性函数中的this指的是当前对象
var name="app"
var o={
name:'test',
sayName:function(){
    console.log(this.name);
 }
}
o.sayName();//test
// 赋值对象属性中的函数时  此时函数为普通函数,获取的this是window 
var sayName2=o.sayName;
sayName2();//app
//对象属性函数中在定义函数,此时的this也是window.
var person={
 sayName:function(){
     (function(){
      console.log(this);
     })()
     
 }
}
person.sayName();//window

// 临时赋值this到闭包函数中
var person={
 sayName:function(){
     var that=this;
     (function(that){
      console.log(that);
     })(that)    
 }
}
person.sayName();//sayName(){}

作为 call/apply/bind 方法的调用

其中call,apply是改变上下文的,本身不是专门做继承的,这点要理解好。(bind绑定的是新函数,后面补充说明),注意call是对象指向加参数列表,apply是对象指向加数组。

  var animal=function(name){
      this.name=name;
      this.yell=function(){
          return this.name;
      }
  }
  var dog=function(name){
      animal.call(this,name);
  }
  var xiaogou=new dog('xiaogou');
  console.log(xiaogou.yell());//xiaogou

作为构造函数使用

此时必须通过new关键字实例化,this才会指向新建的对象,如果按照普通函数执行,就会指向window,如第一种情况的描述。另外需要注意的是,如果函数显性的返回一个对象,那么返回的将是你定义的对象,而不是this对象,只有在返回非对象类型或者不返回时返回的才是this对象。

var animal=function(name){
  this.name=name;
  this.yell=function(){
      return this.name;
  }
}
var dog=new animal("dog");
console.log(dog.yell());//dog
//返回普通数据类型或者不返回时
var myClass=function(){
this.name='anne'
return 'danny'
}
var obj=new myClass()
alert(obj.name)//anne
// 返回对象类型时
  var myClass2=function(){
this.name='anne'
return {
name :'danny'}
}
var obj=new myClass2()
alert(obj.name)//danny

箭头函数

箭头函数里面 this 始终指向外部对象,因为箭头函数没有 this,因此它自身不能进行new实例化,同时也不能使用 call, apply, bind 等方法来改变 this 的指向。(如果两个箭头函数都换成常规函数,那么就会变成指向window)

  var person = {
  name: 'Abby',
  sayName: function() {   
          return (() => {
              console.log(this);   //Object {name: "Abby"}
              console.log(this.name); //Abby
          })()
  }
}
person.sayName();

严格模式

在严格模式下,在全局环境中执行函数调用的时候 this 并不会指向 window 而是会指向 undefined

'use strict';
 function person() {
console.log(this); //undefined
};
person();

setTimeout、setInterval中的this

javascript 高级程序设计》中写到:“超时调用的代码都是在全局执行域中执行的”。setTimeout/setInterval 执行的时候,this 默认指向 window 对象,除非手动改变 this 的指向。

var name = 'Jane';
function Person(){
  this.name = 'Abby';
  this.sayName=function(){
  	console.log(this); //window
      console.log(this.name); //Jane
      };
  setTimeout(this.sayName, 10);
  }

var person=new Person();  

构造函数 prototype 属性

var name = 'Jane';
function Person(){
  this.name = 'Abby';
}
Person.prototype.sayName = function () {
  console.log(this);        // Person {name: "Abby"}
  console.log(this.name);      // Abby
}
var person = new Person();
person.sayName(); 

在 Person.prototype.sayName 函数中,this 指向的 person 对象。即便是在整个原型链中,this 也代表当前对象的值。

页面事件

在相关的元素交互事件中,this指向的是触发事件的元素,同样你也可以在需要的时候把当前元素当做参数传入,当然如果不传,也可以通过event.target等语法拿到元素。比如:

 <span onclick="event(this)"></span>
 $("button").click(function(){
 console.log(this) ;//指向的是当前元素
 })