一直以来,对this的指向问题一直没有好好理解,最近得空,赶紧恶补一下。
1、涵义
this是什么?
简单说,关键字“this”指向当前代码运行时的对象(当前运行时调用该属性或方法的对象)
this是在函数调用过程中设置的
例子:
function fn() {
return this.name;
}
let a = {
name: '小明',
who: fn
}
let b = a.who;
console.log(a.who()); //this指向a,当前who方法是被a调用
console.log(b()); //this指向window,当前b处于全局环境下,this.b === window.b,所以this指向window
2、this使用环境
全局上下文
在全局上下文环境中,this指向window对象
// 在浏览器中, window 对象同时也是全局对象:
console.log(this === window); // true
let a = 1;
console.log(window.a); //1
this.b = 2;
console.log(window.b); //2
console.log(b); //2
函数上下文
在函数内部,this的值取决于函数被调用的方式。
例子:
function fn() {
return this.name;
}
let a = {
name: '小明',
who: fn
}
let b = {
name: '小红',
who: fn,
c: {
d: fn
}
}
console.log(a.who()); //this指向a
console.log(b.who()); //this指向b
console.log(fn()); //this指向window
console.log(b.c.d()); //this指向b.c,为什么不是指向b呢?那是因为this总是指向直接调用它的最近的对象,this只会向上继承最近的一层,不会继承更上面的层;
let h = b.c.d;
h(); //此时this指向window,因为h处于全局对象中
再看一个例子:
let a = {
b () {
console.log(this);
let c = function () {
console.log(this);
}();
}
}
a.b();
这两个this分别指向什么呢?
//第一个this指向a
//第二个this指向window
为什么会这样呢?
就如开头所说的:在函数内部,this的值取决于函数被调用的方式。
上面例子的函数可以看成如下的变体:
let d = function () {
console.log(this);
}
let a = {
b () {
console.log(this);
let c = d();//此时,d相当于是被window调用,所以this此时指向window
}
}
a.b();
那如果我们还是要坚持第一种写法,那可以对this事先赋予一个变量来保存
let a = {
b () {
console.log(this);
let self = this;
let c = function () {
console.log(self);
}();
}
}
a.b(); //这样this的值就不会被改变
箭头函数下的this
let a = {
b () {
console.log(this);
let c = () => {
console.log(this);
};
return c;
}
}
a.b(); // 第一个this指向a
a.b()(); // 两个this都指向a
//两个this都绑定到a,这与非箭头函数的绑定结果完成不一样。
//这是因为当使用箭头函数时,this自动绑定到执行上下文的外层函数上
let f = a.b;
f()(); //此时this指向window,因为this是在执行的时候设置。这时候的f是被window调用,所以this指向window;
let f = a.b(); //此时,this指向a。a.b函数已经被调用,所以this此时已经绑定到a上;
f(); //此时的this绑定到哪里呢?没错,还是在a上,这是因为箭头函数中this的值已经被绑定到外层函数上。
this的绑定方法:call、apply、bind
使用call,或者apply方法可以指定this在执行上下文的指向
call与apply的作用相同,它们的区别在于接受参数的方式不一样。call()接受的参数以列表的形式传参,而apply接受的参数以数组的方式传参
例子:call、apply方法
function sum(b) {
return this.a + b;
}
let sum1 = {a: 1};
sum.call(sum1, 2); //3 this绑定到sum1
sum.apply(sum1, [2]); //3 this绑定到sum1
例子:bind方法
ES6新增了绑定this的bind()方法,调动fn.bind(obj)方法,会创建一个与fn具有相同函数体和作用域的函数, 同时this将永久地被绑定到指定的obj对象上。
function fn() {
return this.a;
}
let obj = {
a: 'binded'
}
let bind1 = fn.bind(obj);
console.log(bind1()); //binded
let bind2 = bind1.bind({a: 'binded2'});
console.log(bind2); //binded
下面两种环境中的this,就是我们经常使用的,略过啦
构造函数中的this
构造函数中的this指向new出来的对象(构造的新对象)
事件处理函数中的this
当函数被用作事件处理函数时,this指向当前触发的DOM对象
例子:
<button onclick="alert(this.tagName)">
Show this
</button>
// this指向当前target:button元素