首先,要明白this 既不指向函数自身,也不指函数的词法作用域。this一般存在于函数中,表示当前函数的执行上下文,如果函数没有执行,那么this没有内容,只有函数在执行后this才有绑定。

然后,我们来看看this四种绑定规则,也可以说在四种不同函数执行方式时this的指向。

默认执行:即没有其他绑定规则存在时的默认规则。这也是函数调用中最常用的规则。this指向window,严格模式下指向undefined

  1. function fn(){
  2. console.log(this)
  3. }
  4. fn()

fn()打印到控制台结果为window

开启严格模式后

  1. function fn(){
  2. "use strict"
  3. console.log(this)
  4. }
  5. fn()

fn()打印到控制台结果为undefined

通过对象执行(通过上下文对象执行) obj.fn():当前的执行对象

  1. function fn(){
  2. console.log(this.a)
  3. }
  4. var a = 10;
  5. var obj = {
  6. a:20,
  7. b:fn
  8. }
  9. var obj2 = {
  10. a:30,
  11. b:obj.b
  12. }
  13. obj2.b(); //??

obj2.b(); 打印到控制台结果为30

因为obj2.b();在上述代码中等价于obj2.fn(),所以此时this指向obj2,所以打印结果为30;

  1. function fn(){
  2. console.log(this.a)
  3. }
  4. var a = 10;
  5. var obj = {
  6. a:20,
  7. b:fn
  8. }
  9. var obj2 = {
  10. a:30,
  11. b:obj.b
  12. }
  13. var obj3 = {
  14. a:40,
  15. b:obj2
  16. }
  17. obj3.b.b() //?

obj3.b.b() 打印结果为30

上述代码调用结果为obj3.b->obj2,obj2.b->obj.b->fn,因为this只获取最近一层调用的上下文对象,即obj2

所以结果为30

注意:这里存在一个陷阱,大家在分析调用过程时,要特别小心

  1. function fn() {
  2. console.log( this.a );
  3. }
  4. var a = 2;
  5. var obj = {
  6. a: 3,
  7. b: fn
  8. };
  9. var bar = obj.b;
  10. bar(); //?

bar() 打印结果为2

为什么会这样,obj.b 赋值给bar,那调用bar()为什么没有触发隐式绑定,使用的是默认绑定呢。

这里有个概念要理解清楚,obj.b 是引用属性,赋值给bar的实际上就是fn函数(即:bar指向fn本身)。

那么,实际的调用关系是:通过bar找到fn函数,进行调用。整个调用过程并没有obj的参数,所以是默认绑定,全局属性a。

  1. function fn(){
  2. console.log(this.a)
  3. }
  4. var a=20;
  5. var obj = {
  6. a:20,
  7. b:fn
  8. }
  9. setTimeout(obj.b, 2000);
  10. function setTimeout(cb,t){
  11. // t
  12. cb() //?
  13. }

cb()打印结果为20

同样的道理,虽然参传是obj.fn,因为是引用关系,所以传参实际上传的就是fn对象本身的引用。对于setTimeout的调用,还是 setTimeout -> 获取参数中fn的引用参数 -> 执行 fn 函数,中间没有obj的参与。这里依旧进行的是默认绑定。

  1. function fn(){
  2. console.log(this.a)
  3. }
  4. var obj1= {
  5. a:10
  6. }
  7. var obj2 ={
  8. a:20
  9. }
  10. var obj3 ={
  11. a:30
  12. }
  13. fn.bind(obj1)();
  14. fn.call(obj2);
  15. fn.apply(obj3);

fn.bind(obj1)();打印结果为10

fn.call(obj2); 打印结果为20

fn.apply(obj3);打印结果为30

这里要注意fn.bind(obj1)后面还要加一个括号才执行!

js中的new操作符,和其他语言中(如JAVA)的new机制是不一样的。js中,它就是一个普通函数调用,只是被new修饰了而已。

使用new来调用函数,会自动执行如下操作:

如果函数没有返回其他对象,那么new表达式中的函数调用会自动返回这个新对象。
从这点可以看出,this指向的就是对象本身。

  1. function foo(a) {
  2. this.a = a;
  3. }
  4. var a = 2;
  5. var bar1 = new foo(3);
  6. console.log(bar1.a); // ?
  7. var bar2 = new foo(4);
  8. console.log(bar2.a); // ?

因为每次调用生成的是全新的对象,该对象又会自动绑定到this上,所以打印结果分别为3,4

优先级是这样的,以按照下面的顺序来进行判断:
数是否在new中调用(new绑定)?如果是的话this绑定的是新创建的对象。
数是否通过call、apply(显式绑定)或者硬绑定调用?如果是的话,this绑定的是 指定的对象。
数是否在某个上下文对象中调用(隐式绑定)?如果是的话,this绑定的是那个上下文对象。
果都不是的话,使用默认绑定。如果在严格模式下,就绑定到undefined,否则绑定到 全局对象。

版权声明:本文为mhcll原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/mhcll/p/11439900.html