JS中关于this的五种情况汇总

JS中 this 的五种情况汇总

1、事件绑定:
给当前元素的某个事件绑定方法,当事件行为触发,方法被执行,方法中的this一般都是当前操作的元素
排除:IE6~8中,基于attachEvent进行的DOM2事件绑定,方法中的this是window

 // 例如:
 document.body.onclick = function(){
  console.log(this); // body元素
}
document.body.addEventListener('click', function(){
  console.log(this);// body元素
})
复制代码

2、函数执行(包括自执行函数)
函数执行,看函数前面有没有点“.”,有点,则点前面是谁,函数中的this就是谁;没有点,则this是window
+ 在严格模式下,没有点,this是undefined
+ 匿名函数(自执行函数/回调函数)执行,一般this也是window(严格模式下是undefined),除非有特殊处理

// 例如:
// "use strict"
 function fn(){
  console.log(this);
}
let obj = {
  name: 'obj',
  fn: fn
}
//函数前面没有点
fn(); // window/undefined
// 函数前面有点
obj.fn(); // obj
// 自执行函数
(function(){
  console.log(this); // window/undefined
})();
// 回调函数
[1,2].forEach(function(a,b){
  console.log(this); // window/undefined
}); 
复制代码

3、new 构造函数
构造函数执行(new xxx),函数体中的this是当前类的实例

// 例如:
function Fn(){
  this.name = '构造函数';
  console.log(this);
}
Fn.prototype.sum = function(){}
let f = new Fn; // this -> f
Fn(); // this -> window
f.sum(); // this ->f
f.__proto__.sum(); // this -> f.__proto__ 
复制代码

4、箭头函数
ES6中的箭头函数(或者基于{}形成的块级上下文),里面没有this,如果代码中遇到this也不是它自己的,而是它所在上下文中的this

// 例如:
 let obj = {
  name: 'obj',
  fn: function(){
    // obj.fn()执行: this ->obj
    console.log(this);
    setTimeout(function(){
      console.log(this); // window 因为这是一个回调函数
    },500);

    setTimeout(() => {
      // 这里的this用的是上级上下文中的this
      console.log(this); // obj
    }, 1000)
  }
}
obj.fn(); // fn中的this-> obj 
复制代码

5、call/apply/bind
基于Function.prototype上的call/apply/bind方法强制改变函数中的this执行(注意:该结论对箭头函数没用,因为箭头函数中没有自己的this)

// 例如:
let obj = {
  name: 'obj',
  fn:fn
};
function fn(){
  console.log(this);
}
fn(); // window
obj.fn();  // obj
fn.call(obj); // obj
console.log(fn.call(obj));  // undefined
obj.fn.apply(window); // window
复制代码
关于call/apply/bind 的使用

=== call ===
语法:函数.call(context, parm1, parm2, …)
简单说明:把函数执行,让函数中的this指向context,并且把parm1、parm2…作为实参传递给函数
详细说明:
+ 首先函数基于原型链__proto__找到Function.prototype.call方法,并且把call方法执行
+ call方法中的this就是当前操作的Function的实例—函数,传递给call方法的第一个实参是要函数中this的指向,剩余实参是依次要传递给函数的参数
+ call方法执行的过程中,实现了这样的处理:把 函数[call中的this] 执行,让 函数中的this指向context,并且把剩余实参传递给函数。如果一个参数也不传,或者第一个参数传递的是null/undefined,给严格模式下,最后函数中的this都是window(严格模式下,不传是undefined,传了null/undefined,最后函数中的this也会改为对应的值)

=== apply ===
语法:函数.apply(context, [parm1, parm2,…])
对比call和apply的区别只有一个,执行函数的时候,需要传递给函数的参数信息,在最开始传递给call/apply的时候,形式不一样
1、call 是需要把参数一个一个的传递给call
2、apply 是需要把参数放在一个数组中传递给apply

=== bind ===
语法:函数.bind(context,param1,param2,…)
call/apply在执行的时候,都会立即把要操作的函数执行,并且改变它的this指向。
bind 是预先处理:指向bind只是预先把函数中需要改变的this等信息改变了并存储起来,此时函数并不会被立即执行,执行完bind会返回一个匿名函数,当后期执行匿名函数的时候,再去把之前需要执行的函数执行,并且改变this的指向。

let a = fn.bind(obj); // 执行bind的时候,fn是不会执行的
console.log(a); // 执行bind会返回一个函数,后期只有手动调用a()才会把里面的fn执行,并且按照执行bind时传递的this指向改变fn中的this值

// 需求:1s后执行fn,并且让fn中的this变为obj,传递10,20
setTimeout(fn.call(obj, 10, 20), 1000); // 这样写虽然this和参数都是想要的,但是并没有在1s后才执行,而是立即就执行了,这是因为在设置定时器的时候,已经基于call方法把fn给执行了
setTimeout(fn.bind(obj, 10, 20), 1000); // 把bind执行完后的结果(一个匿名函数)绑定给定时器,1s之后执行这个匿名函数
复制代码
© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享