普通函数和箭头函数的this

普通函数的this

1. this总是代表它的直接调用者, 例如 obj.func ,那么func中的this就是obj

2. 调用的时候,没有任何前缀,则指向window,new的时候,指向new出来的对象。

3.在默认情况(非严格模式下,未使用 'use strict'),没找到直接调用者,则this指的是 window

4.在严格模式下,没有直接调用者的函数中的this是 undefined

5.使用call,apply,bind(ES5新增)绑定的,this指的是 绑定的对象

全局环境下

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

console.log(this.document===document)   //true

console.log(this===window);             //true

this.a=12;
console.log(window.a);                  //12

函数上下文调用

函数直接调用

普通函数内部的this分两种情况,严格模式和非严格模式。

非严格模式下,this 默认指向全局对象window

function f1(){
    return this;
}

console.log( f1() === window ); // true

而严格模式下, this为undefined

function f2(){
    "use strict"; // 这里是严格模式
    return this;
}
console.log( f2() === undefined ); // true

对象中的this

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

  1. 函数的定义位置不影响其this指向,this指向只和调用函数的对象有关
  2. 多层嵌套的对象,内部方法的this指向离被调用函数最近的对象(window也是对象,其内部对象调用方法的this指向内部对象, 而非window)。
//1.
var prop=10
var o = {
    prop: 20,
    f: function() {
        return this.prop;
    }
};
console.log(o.f());  //20


//2.
var a = o.f;         //此时“return this.prop;”中的this指向了window
console.log(a());    //10    如果window中没有prop变量,则返回undefined


//3.
var o = {prop: 30};
function independent() {
    return this.prop;
}

console.log(o.f);     //undefined,后面定义的对象o覆盖了之前的对象,此时f函数不存在
// console.log(o.f());   //o.f is not a function
o.f = independent;    //此时,independent()函数中的this指向的是后面定义的o对象
console.log(o.f);     //ƒ independent() {return this.prop;}
console.log(o.f());   // 30

//4.
function independent1() {
    return this;
}
o.b = {
    f:independent,
    f1:independent1,
    prop: 42
};
console.log(o.b.f()); //   42
console.log(o.b.f1()); //  {f: ƒ, f1: ƒ, prop: 42},此时的this指向的是o.b对象,就近原则

原型链中this

原型链中的方法的this仍然指向调用它的对象,与以上讨论一致;看个例子,

var o = {
    f : function(){
        return this.a + this.b;
    },
    f1:function () {
        return this;
    }
};
var p = Object.create(o);
p.a = 1;
p.b = 4;

console.log(p.f());   // 5
console.log(p.f1());  //{a: 1, b: 4}
console.log(o.f());   //NaN
console.log(o.f1());  //{f: ƒ, f1: ƒ}

可以看出, 在p中没有属性f,当执行p.f()时,会查找p的原型链,找到 f 函数并执行,但这与函数内部this指向对象 p 没有任何关系,只需记住谁调用指向谁。

以上对于函数作为getter & setter 调用时同样适用。

构造函数中this

构造函数中的this与被创建的新对象绑定。

注意:当构造器返回的默认值是一个this引用的对象时,可以手动设置返回其他的对象,如果返回值不是一个对象,返回this。

//1.
function C1(){
    this.a = 37;
}
var o1 = new C1();
console.log(o1.a); //  37

//2.
function C2(){
    return this;
}
var o2 = new C2();
console.log(o2); //  C2{}

//3.
function C3(){
    this.a = 37;
    return {a:38};
}
var b = new C3();
console.log(b.a); //  38

以上两个例子内部的this都指向对象o, 看到这里的你不妨在控制台执行下以上代码,看看对象 o 和 b ,这些是属于构造函数的内容了,此处不多做介绍。(C3函数中的this.a = 37 对整个过程完全没有影响的, 可以被忽略的)。

DOM 事件处理函数中的 this & 内联事件中的 this

DOM事件处理函数

  1. 当函数被当做监听事件处理函数时, 其 this 指向触发该事件的元素 (针对于addEventListener事件)
function bluify(e) {
//    在控制台打印出所点击的元素
    console.log(this);
//    阻止事件冒泡
    e.stopPropagation();
//    阻止默认事件
    e.preventDefault();
//    当前元素的背景颜色改变
    this.style.backgroundColor="red"
}

var el=document.getElementsByTagName("div");

for(var i=0;i<el.length;i++){
    el[i].addEventListener('click',bluify,false)   //默认false,在冒泡阶段执行
}

内联事件
内联事件中的this指向分两种情况:

  1. 当代码被内联处理函数调用时,它的this指向监听器所在的DOM元素
  2. 当代码被包括在函数内部执行时,其this指向等同于 ****函数直接调用****的情况,即在非严格模式指向全局对象window, 在严格模式指向undefined
<button onclick="console.log(this);"></button>        
<!--<button onclick="console.log(this);"></button>--> 
<button onclick="(function() {console.log(this);})()"></button>
<!--window--> 
<button onclick="(function () {'use strict';console.log(this);})()"></button>
<!--undefined--> 

 

setTimeout & setInterval

对于延时函数内部的回调函数的this指向全局对象window(当然我们可以通过bind方法改变其内部函数的this指向)

//默认情况下代码
function Person() {
    this.age = 0;
    setTimeout(function() {
        console.log(this);
    }, 1000);
}

Person()                  //window
var p = new Person();     //1秒后返回 window 对象

// 通过bind绑定
function Person1() {
    this.age = 0;
    setTimeout((function() {
        console.log(this);
    }).bind(this), 1000);
}

var p = new Person1();     //1秒后返回构造函数新生成的对象 Person{...}
Person1();                 //window

例子:

eg01:

解析:谁调用的函数,函数体中的this就指向谁

eg02:

解析:这次this指向了最外层的window对象,为什么呢,还是那个道理,这次this出现在全局函数setTImeout()中的匿名函数里,并没有某个对象进行显示调用,所以this指向window对象,因此调用了window中num的值

eg03:

 var obj = {
      func: function() {
          console.log(this);      //Object
      },
      say: function () {
          var that = this;   //此时的this就是obj对象
          setTimeout(function () {
              console.log(this)   //Window
              that.func()
          });
      }
}
  obj.say();

解析:匿名函数,定时器中的函数,由于没有默认的宿主对象,所以默认this指向window, 如果想要在setTimeout中使用这个对象的引用,需要先将this存起来,我们通常使用that = this, 或者 _this = this来保存我们需要的this指针!

eg04:

 window.val = 1;
 var obj = {
       val: 2,
       dbl: function () {
          console.log(val);       //1
          console.log(this.val);  //2

          this.val *= 2;
          val *= 2;
                
          console.log(val);       //2
          console.log(this.val);  //4
        }
 };

obj.dbl();

解析:

val变量在没有指定对象前缀,默认从所属的函数中找(即从db1函数中找,该函数作用域内没有val变量),找不到则从window中找全局变量

即 val *=2 就是 window.val *= 2

this.val默认指的是 obj.val ;因为 dbl()第一次被obj直接调用

eg05:

window.val = 1;
var obj = {
     val: 2,
     dbl: function () {
         console.log(this);      //Window
         console.log(val);       //1
         console.log(this.val);  //1

         this.val *= 2;
         val *= 2;

         console.log(val);       //4
         console.log(this.val);  //4
     }
};

var func=obj.dbl;
func();

归纳:

func() 没有任何前缀,类似于全局函数,即  window.func调用,所以此时调用的时候, this指的是window, val指的是window.val,this.val也指的是window.val

**********************************************************************************************************************************************************

箭头函数的this

默认指向在定义它时,它所处的对象,而不是执行时的对象, 定义它的时候,可能环境是window(即继承父级的this);

箭头函数表达式的语法比函数表达式更简洁,并且没有自己的thisargumentssuper或 new.target。这些函数表达式更适用于那些本来需要匿名函数的地方,并且它们不能用作构造函数。

箭头函数不会创建自己的this,它只会从自己的作用域链的上一层继承this。因此,在下面的代码中,传递给setInterval的函数内的this与封闭函数中的this值相同:

function Person(){
    this.age = 0;

    setTimeout(() => {
        this.age++; // this 指向 Person
        console.log(this);   //指向Person ,且age=1
    }, 1000);
}

var p = new Person();
console.log(p);             //指向Person ,且 age=0

eg01:

var obj = {
    say: function () {
        setTimeout(() => {
            console.log(this)
        });
    }
}
obj.say(); // obj

此时的this是定义它的对象,即继承了父级的this,父级中的this指的是obj,而非window

eg02:

var obj = {
    say: function () {
      var f1 = () => {
        console.log(this); // obj
        setTimeout(() => {
          console.log(this); // obj
        })
      }
      f1();
    }
  }
  obj.say()

f1继承父级this指代的obj,不管f1有多层箭头函数嵌套,都是obj.

eg03:

var obj = {
    say: function () {
      var f1 = function () {
        console.log(this);    // window, f1调用时,没有宿主对象,默认是window
        setTimeout(() => {
          console.log(this); // window
        })
      };
      f1();
    }
  }
  obj.say()

第一个this:f1调用时没有宿主对象,默认是window

第二个this:继承父级的this,父级的this指代的是window.

eg04:

//1
var x=1;
var obj={
    x:2,
    say:()=>{
        console.log(this);     // window
        console.log(this.x);   // 1
    }
}
obj.say();

//2
var a=3;
function test(){
    this.a=4;
    var fn=()=>{
        console.log(this);      //test
        console.log(this.a)     //4
    }
    fn();
}
var x=new test();

//3
var b=5;
function test2(){
    this.b=6;
    let func=()=>{
        console.log(this);     //window
        console.log(this.b)    //6
    }
    func();
}
test2();

第一个:ES6中定义的时候绑定this的继承的是父执行上下文里面的this,普通对象(非函数是,没有执行上下文的),因此第一个的this指向了window

第二个:this指向new出来的对象,即test

第三个:test2() 没有任何前缀,类似于全局函数,即  window.test2调用,所以此时调用的时候, this指的是window,

执行上下文(Execution Context)

执行上下文可以理解为函数执行的环境,每一个函数执行时,都会给对应的函数创建这样一个执行环境。

每次当控制器转到可执行代码的时候,就会进入一个执行上下文。执行上下文可以理解为当前代码的执行环境,它会形成一个作用域。JavaScript中的运行环境大概包括三种情况。

  • 全局环境:JavaScript代码运行起来会首先进入该环境
  • 函数环境:当函数被调用执行时,会进入当前函数中执行代码
  • eval(不建议使用,可忽略)

因此在一个JavaScript程序中,必定会产生多个执行上下文,JavaScript引擎会以栈的方式来处理它们,这个栈,我们称其为函数调用栈(call stack)。栈底永远都是全局上下文,而栈顶就是当前正在执行的上下文。当代码在执行过程中,遇到以上三种情况,都会生成一个执行上下文,放入栈中,而处于栈顶的上下文执行完毕之后,就会自动出栈。



作者:这波能反杀
链接:https://www.jianshu.com/p/a6d37c77e8db
來源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。

参考:
https://www.cnblogs.com/lemonmonster/p/8482232.html

https://www.cnblogs.com/var-chu/p/8476464.html

https://www.cnblogs.com/dongcanliang/p/7054176.html

  • 18
    点赞
  • 56
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值