能够先经过一个例子了解下javascript
function speak(){ var name = this.name console.log("Hello I am --" + name) } var me = { name: 'a', speak: speak } var you = { name: 'b', speak: speak } me.speak() //Hello I am -- a you.speak() //Hello I am -- b 复制代码
this能够在同一个执行环境中使用不一样的上下文对象。它其实提供了一种更加优雅的方式来隐式“传递”一个对象引用,所以可使API设计的更加简洁且易于复用。java
其实关于this的指向问题能够从函数的执行调用过程当中理解,当一个函数被调用时,会建立一个活动记录(执行上下文)。这个记录会包含函数在哪里被调用、函数的调用方法、传入的参数等信息,this也是这里的一个属性。当函数被某个对象调用时能够理解为在函数调用的那一刻它被调用对象拥有。因此this指向调用其的对象。windows
对于this的指向问题,通常都是根据以上的解释去理解,虽然在通常的状况下这样的理解是不会有问题的,可是当在某些场景下这样的解释并非很准确,因此会让人感受一直琢磨不透的感受。今天能够就不一样状况展开讨论下this指向的问题。看看下面的打印结果会是什么数组
// 例子1 function test(){ var a = 10; console.log(this.a); console.log(this); } test(); // 例子二 var b = 10; var o = { b: 20, fn:function(){ console.log(this.b); } } o.fn(); 复制代码
按照上面的定义this最终指向的是调用它的对象,这里的函数test实际是被Window对象所点出来的。因此例子1中的this指向的是windows。在例子2中函数的执行是经过o.fn()调用的,因此this的指向的固然是对象o了。这两个例子能够验证上面的定义,可是仍是不够准确的。markdown
// 例子三 var b = 10; var o = { b: 20, fn:function(){ console.log(this.b); } } window.o.fn(); 复制代码
此时打印的应该是什么呢?这段代码和上面的那段代码几乎是同样的,可是这里的this为何不是指向window,若是按照上面的理论,最终this指向的是调用它的对象,在此处就显得不是很准确了。因此关于函数中this的指向实际上是能够分为三种状况的app
// 例子4 var o = { a:10, b:{ a:12, fn:function(){ console.log(this.a); console.log(this); } } } var j = o.b.fn; j(); 复制代码
此处的this指向的是window,其实这里只须要理解清楚一句话"this永远指向的是最后调用它的对象",也就是看它执行的时候是谁调用的,例子4中虽然函数fn是被对象b所引用,可是在将fn赋值给变量j的时候并无执行因此最终指向的是window,这和例子3是不同的,例子3是直接执行了fn。因此说,那例子5中的打印结果又应该是什么呢?函数
// 例子5 function foo() { console.log( this.a ); } var obj = { a: 2, foo: foo }; var bar = obj.foo; // 函数别名! var a = "xxxxx" bar(); 复制代码
1.构造函数版thisthis
// 例子6 function Fn(){ this.user = "lh"; } var a = new Fn(); console.log(a.user); 复制代码
这里之因此对象a能够点出函数Fn里面的user是由于new关键字能够改变this的指向,将这个this指向对象a,咱们这里用变量a建立了一个Fn的实例(至关于复制了一份Fn到对象a里面),此时仅仅只是建立,并无执行,而调用这个函数Fn的是对象a,那么this指向的天然是对象a,那么为何对象Fn中会有user,由于已经复制了一份Fn函数到对象a中,用了new关键字就等同于复制了一份。spa
!当this赶上return时设计
// 例子7 function fn() { this.user = 'lh'; return {}; } var a = new fn; console.log(a.user); // 例子8 function fn() { this.user = 'lh'; return function(){}; } var a = new fn; console.log(a.user) // 例子9 function fn() { this.user = 'lh'; return 1; } var a = new fn; console.log(a.user); 复制代码
由上可知,若是返回值是一个对象,那么this指向的就是那个返回的对象,若是返回值不是一个对象那么this仍是指向函数的实例。
2.箭头函数中的this
var x=11; var obj={ x:22, say:()=>{ console.log(this.x); } } obj.say(); 复制代码
箭头函数不是经过function关键字定义的,也就不遵循以上的this规则,而是“继承”外层做用域中的this指向。箭头函数中的this是在定义函数的时候绑定,而不是在执行函数的时候绑定。所谓的定义时候绑定,就是this是继承自父执行上下文!!中的this,好比这里的箭头函数中的this.x,箭头函数自己与say平级以key:value的形式,也就是箭头函数自己所在的对象为obj,而obj的父执行上下文就是window,所以这里的this.x实际上表示的是window.x,所以输出的是11。
var a = { user:"lh", fn:function(){ console.log(this.user); } } var b = a.fn; b(); 复制代码
var a = { user:"lh", fn:function(){ console.log(this.user); } } var b = a.fn; b.call(a); 复制代码
经过在call方法,给第一个参数添加要把b添加到哪一个环境中,也就是说,this就会指向那个对象。 call方法除了第一个参数之外还能够添加多个参数,以下
var a = { user:"lh", fn:function(p1, p2){ console.log(this.user) console.log(p1+p2) } } var b = a.fn; b.call(a, 1, 3) 复制代码
var a = { user:"lh", fn:function(p1, p2){ console.log(this.user) console.log(p1+p2) } } var b = a.fn; b.apply(a, [1, 3]) 复制代码
bind()方法也可用来改变this的指向,可是和call,apply方法在用法上有区别,以下:
var a = { user:"lh", fn:function(){ console.log(this.user); } } var b = a.fn; b.bind(a); 复制代码
此时发现并不打印任何的结果,这是由于bind方法返回的是一个修改事后的函数,此时执行conole.log(b.bind(a))会获得的结果是:
ƒ () { console.log(this.user); } 复制代码
call和apply都是改变上下文中的this并当即执行这个函数,bind方法可让对应的函数想何时调就何时调用,而且能够将参数在执行的时候添加,这是它们的区别,根据本身的实际状况来选择使用。而且也是能够像call和apply同样传递参数