javacript中的this指向问题

this提供了一种更优雅的方式来“传递一个对象的引用
 
1 浏览器全局环境和node全局环境中的this
浏览器中的this指向windows,window为浏览器的全局对象。
console.log(this===window);//true
node环境中this指向为一个空对象。而global为node的全局对象。
console.log(this);//{},
console.log(this===global)://false
 
2 箭头函数和function关键字函数的this指向总结。
2.1 function关键字函数
(1)一般情况this 指向它的调用对象,如果没有调用者则指向全局对象。
(2)在构造函数下(也就是new function()),this指向被创建的新对象。
(3)在使用js监听dom事件情况下,this指向触发事件的元素。
(4)apply,call和bind可以强制改变this的指向,使this的指向为三个处理方法中上送的一个参数对象。
 (5) 在html元素上使用内联事件时,如果调用js中方法或书写代码的情况下this指向当前元素。如果在事件直接使用()()立即执行,则非严格模式下this指向window,严格模式下指向undefined。
2.2 非箭头函数
  指向箭头函数定义时所处的对象,而不是箭头函数使用(调用)时所在的对象,默认使用父级的this。
  this等同于上一层非箭头函数的this值或全局对象(window或undefined)(严格模式this是undefined)
 
3 各种情况下的示例分析。
3.1 在全居环境下定义和调用。
function 关键字定义函数 
function fun(){
    // "use strict"; // 这里是严格模式
    return this;
}
//true  浏览器环境  这里是非严格模式  在严格模式下指向undefined
console.log(fun()===window); 
 //treu  node环境  这里是非严格模式  在严格模式下指向undefined
console.log(fun()===global);
箭头函数  
let foo=()=>{
  //  "use strict"; // 这里是严格模式
  return this;  
}
this.a="5";
//true 浏览器环境。严格模式与非严格模式一致
console.log(foo()===window); 
//true node环境下 全局的this为一个空对象{},所以这里this指向的是空对象。严格模式与非严格模式一致
console.log(foo()===this);
//很显然这里定义的箭头函数指向的是,定义位置所处环境的this。严格模式与非严格模式一致
console.log(foo());//{a:'5'},
3.2 对象中this的调用
function 关键字定义函数 
let obj={
    a:"aa",
    foo:function(){
        return this;
    }
}
//true  浏览器环境与node环境一致。
console.log(obj.foo()===obj);
//obj中没有this这个属性,这里等于undefined。 
//console.log(obj.this); 
let a=obj.foo;
console.log(a())   //node 为global  浏览器为window
注:对于多层嵌套对象的调用,内部方法的this指向离被调用函数最近的对象(window也是对象,其内部对象调用方法的this指向内部对象, 而非window)。
箭头函数 
let obj={
    a:"aa",
    foo:()=>{
        return this;
    }
}
//true  浏览器环境与node环境一致。
console.log(obj.foo()===window); 
//在node中,指向全局this中指向的空对象。
this.a="aa";
//{a:'aa'} node环境
console.log(obj.foo());
注:对于嵌套的多层对象来说,都是指向window。
 
3.3 构造函数中的this
function 关键字定义函数 
当构造函数没有返回时 this指向new 所以创建的新对象。 浏览器环境与node环境是一致的。
function C(){
    console.log(this); //{}
    this.a='a'; 
}
let d=new C();
console.log(d);//{a:'a'}
注:由于箭头函数的this更像是进行了某种操作透传(继承)作用域的this,因此箭头函数我的理解是没有this的, 所以箭头函数不能作为构造函数。会抛出一个VM1565:5 Uncaught TypeError: C is not a constructor
3.4 call,apply和bind强制改变this的指向
function 关键字定义函数
function foo(){
    console.log(this);
    console.log(...arguments);
}
let a={b:'b',foo:foo};
foo();  //浏览器环境输出 window ;node环境输出 global
a.foo(); //输出a对象。
let c={c1:'c1'}; 
let d=[1,2,3,4];
foo.call(c,...d);//{ c1: 'c1' },1 2 3 4
foo.apply(c,d);//{ c1: 'c1' },1 2 3 4
let foo2 = foo.bind(c,...d);
foo2(88,99); //{ c1: 'c1' } ,1 2 3 4 88 99
注;由于箭头函数没有自身的this,它的this是继承的,所以无法强制改变this的指向。箭头函数也没有arguments。
但如果强制使用不能改变其this指向。可以传入函数定义时的指定参数个数。
let foo=(a,b,c)=>{
    console.log(this); //浏览器环境 this都输出为window。node环境 this都输出为{}
    console.log(a,b,c);//都输出为1,2,3
}
let c={c1:'c1'}; 
let d=[1,2,3,4];
foo.call(c,...d);
foo.apply(c,d);
let foo2 = foo.bind(c,...d);
foo2(88,99); 
 
3.5 dom事件和内联事件
dom绑定事件
  <div>我是dom绑定事件</div>
   <span>我是span</span>
   <button >哈哈哈</button>
   <script>
      // 被调用时,将关联的元素变成蓝色
      function doClick(e){
      //在控制台打印出所点击元素
      console.log(this);
      //阻止时间冒泡
      e.stopPropagation();
      //阻止元素的默认事件
      e.preventDefault();      
      this.style.backgroundColor = '#A5D9F3';
    }
    // 获取文档中的所有元素的列表
    var elements = document.getElementsByTagName('*');
    // 将bluify作为元素的点击监听函数,当元素被点击时,就会变成蓝色
    for(var i=0 ; i<elements.length ; i++){
      elements[i].addEventListener('click', doClick, false);
    }
    </script>

内联事件:

 <button onclick="console.log(this)" >click me </span>
 <button onclick="(function(){console.log(this)})()" >Non strict mode</span>
 <button onclick="(()=>{console.log(this)})()" >Non strict mode Arrow function </span>
 <button onclick="(function(){'use strict'; console.log(this)})()" >use strict</button>

 

3.6 setTimeout & setInterval
function 关键字定义函数 
let a={a:'aa'};
setTimeout(function(){console.log(this)},2000);  //浏览器环境过两秒输出 window ;node环境输出 一个Timeout对象。
setTimeout((function(){console.log(this)}).bind(a),3000); //可通过bind改变this指向
箭头函数 
setTimeout(()=>{console.log(this)},2000); //浏览器环境,输出window,node环境输出{}
最后个人总结:箭头函数本身是没有this的,其this是继承函数定义(如果定义的作用域也是箭头函数,则往上继续继承,知道作用域有this为止)时所处作用域链中离它最近的this。
非常感谢很多前辈的优秀博客为我提供了巨大的帮助,感谢名单在此不一一列举。本博客仅供参考学习,不做盈利目的。如果错误,欢迎指正。
 
原文地址:https://www.cnblogs.com/bojunyixiao/p/15232076.html