一,this的概念
this是指当前函数执行的主体(并非上下文),也就是谁把函数执行的,this就指向谁。
this的指向是在函数被执行调用的噬魂确定的,而不是在定义的时候确定。
二,this的指向
2.1 在全局环境中
在全局中,this指向window;
严格模式时,this指向undefined
2.2 在函数内部
在函数内部,this的指向主要取决于函数的调用方式。可以看执行主体前面是否有个点,如果有,就指向点前面的对象;如果没有,就指向window(严格模式下为undefined)。
(1)有点(即函数作为对象的一个属性被调用):
var obj = {
title: 'xxx',
eating: function() {
console.log(this);
}
}
obj.eating(); // 执行主体前面有个点,点前面是obj,即this指向obj
(2)没有点(即函数直接被调用执行):
var obj = {
title: 'xxx',
eating: function() {
console.log(this);
}
}
var eat = obj.eating;
eat(); // 执行主体前面没有点,直接被调用,即this指向window
2.3 在构造函数中
this指向当前的实例。
注意:仅限于通过new关键字实例化的实例。否则,this函数遵循以上普通函数的规则。
function Person{
this.a = '1';
this.b = '2';
console.log(this);
}
var p1 = new Person(); // 执行主体是作为构造函数,即this指向实例p1
Person(); // 执行主体属于普通函数,即this指向window
2.4 在自执行函数中
this指向window,严格模式下this指向undefined
2.5 回调函数中
this一般都指向window
2.6 ES6箭头函数中
箭头函数中没有this。如果非要引用,就会到上级作用域去找,直到找到window
2.7 给元素绑定事件,事件里的this
指向当前被绑定的元素本身
btn.onclick = function() {
console.log(this); // this指向被绑定的元素本身,即btn
}
三,改变this的指向
- 每个函数都是Function的实例,所以每个函数.__prototype === Function.prototype;
- 由上可以说明,每个函数都可以调用Function原型上的方法,譬如call、apply、bind。这几个方法都是Function原型中提供的,主要是用来改变函数内部的this指向
- 所以,每个函数的call和apply方法,是不会被继承的
3.1 call方法
语法:函数.call(context,params1,params2....)
说明:执行当前函数,同时改变当前函数的this指向为第一个参数;将其他参数当做函数的参数传入
示例:
var obj = { name: '张三' };
function eat(a, b) {
console.log(this, a, b);
}
eat.call(obj, 10, 20); // this指向变为obj对象
原理:
如上图,一个不相关的对象和一个函数,我们的目的实际是在调用eat函数时,this指向obj对象,也就是obj.eat(),this指向obj。但是obj对象中没有eat属性,因此直接调用会报错,所以call的原理可以理解为:
(1)先给对象添加一个函数属性
(2)然后通过对象.函数属性执行函数(这样this便指向了对象)
(3)最后因为对象本身没有eat函数属性,需要通过delete删除它
obj.eat = eat; // 将eat()函数赋值给obj对象的eat属性
obj.eat(); // this指向obj
delete obj.eat; // 删除obj的eat属性
3.2 apply方法
apply和call的作用一样,唯一的不同就是传参方式,call是一个个参数传入,apply是传入一个数组。
fn.call(obj, 10, 20);
fn.apply(obj, [10, 20]);
3.3 bind方法
语法:函数.bind(context,params1,params2....)
说明:与call和apply用法一样,都是改变this指向,但是bind只改变this指向,不执行函数。
其他区别:bind方法的返回值是改变this指向之后的一个新函数