this的指向性问题
前言
this是一个抽象化的概念,在不同的场景有着不同的指向,它就像一个魔术变量,有着千变万化,不过只要我们掌握核心,就能很清楚的分辨它具体指向哪里。
一、默认绑定
1 函数直接调用
js非严格模式下,函数在调用时没有任何前缀时,函数里的this默认指向全局变量window。
代码如下(示例):
function fn1() {
let fn2 = function () {
console.log(this); //window
fn3();
};
console.log(this); //window
fn2();
};
function fn3() {
console.log(this); //window
};
fn1();
2 行内绑定
<div class="box">
<button type="button" id="btn" onclick="fn()">我是一个按钮</button>
</div>
<script>
function fn() {
console.log(this); //btn
}
</script>
二、隐式绑定
如果函数调用时,前面有调用它的对象,this就隐式绑定在这个对象上
1.对象调用
this在对象中表示当前对象本身。
var obj={
a:"哈哈哈",
b:function(){
console.log(this);
}
};
obj.b();//Object
2.动态绑定的事件
在动态绑定的事件的回调函数中,this指向当前节点对象
代码如下(示例):
<div class="box">
<button type="button" id="btn">我是一个按钮</button>
</div>
<script>
var btn = document.getElementById("btn");
btn.onclick = function () {
console.log(this); //btn
}
</script>
三.this显式绑定
显式绑定是指我们通过call、bind方法改变this的行为,相比隐式绑定,我们能清楚的感知 this 指向变化过程。来看个例子:
代码如下(示例):
let obj1 = {
name: '加薪*1'
};
let obj2 = {
name: '加薪*2'
};
var name = '加薪';
function fn() {
console.log(this.name);
};
fn(); //加薪 指向window
fn.call(obj1); //加薪*1 指向object1
fn.bind(obj2)(); //加薪*2 指向object2
四.new绑定
要想知道js中new以后this指向了谁,必须的知道new做了哪些事:
1.在内存中创建一个新的空对象
2.让this指向这个新的对象
3.执行构造函数里面的代码,给这个新对象添加属性和方法
4.返回这个新对象
function Fn(){
this.name = '加薪加薪';
};
let obj = new Fn();
obj.name//加薪加薪 this指向被实例化后的对象
五. 箭头函数的this
箭头函数中this指向宿主对象,准确的说,箭头函数中没有this,箭头函数的this指向取决于外层作用域中的this,外层作用域或函数的this指向谁,箭头函数中的this便指向谁。
function fn() {
return () => {
console.log(this.name);
};
}
let obj1 = {
name: '加2k月薪'
};
let obj2 = {
name: '加4k月薪'
};
let bar = fn.call(obj1); // fn this指向obj1
bar.call(obj2); //加2k月薪
从第二次结果我们可以看出,再次改变this指向时没有生效,这是为什么呢?
前面说了,箭头函数的this取决于外层作用域的this,fn函数执行时this指向了obj1,所以箭头函数的this也指向obj1。除此之外,箭头函数this还有一个特性,那就是一旦箭头函数的this绑定成功,也无法被再次修改,有点硬绑定的意思。
当然,箭头函数的this也不是真的无法修改,我们知道箭头函数的this就像作用域继承一样从上层作用域找,因此我们可以修改外层函数this指向达到间接修改箭头函数this的目的。
function fn() {
return () => {
console.log(this.name);
};
};
let obj1 = {
name: '听风是风'
};
let obj2 = {
name: '时间跳跃'
};
fn.call(obj1)(); // fn this指向obj1,箭头函数this也指向obj1
fn.call(obj2)(); //fn this 指向obj2,箭头函数this也指向obj2
六.定时器
定时器函数中this指向window,示例如下
var obj = {
fn: function () {
var timer = null;
clearInterval(timer);
timer = setInterval(function () {
console.log(this); //window
}, 1000)
}
}
obj.fn();
但是如果定时器里使用箭头函数则指向会改变,会指向这个对象本身,和隐式绑定中的对象绑定一样,遵循了箭头函数this’指向宿主对象的原则。
var obj = {
fn: function () {
var timer = null;
clearInterval(timer);
timer = setInterval(() => {
console.log(this);//object
}, 1000)
},
}
obj.fn();