关于js的this指向,一直以来碰到的问题还是挺多的,尤其是刚入行的时候,也是面试时屡试不爽的题型。先是ES5的this指向,现在轮到ES6中箭头函数的this了,因为开发中躺过箭头函数的坑,所以这里顺带记一下this的指向问题吧。
ES5中,这个问题相信大家都很熟悉了,在这里主要归结为5类:
1.函数作为普通函数调用,在非严格模式下this指向window,严格模式下this指向undefined
2.函数作为对象的方法调用,this指向调用方法的对象
3.使用new 构造函数创建对象,this指向构造函数内部新创建的对象
4.上下文的方式调用(call | apply),this指向第一个参数
5.定时器中,this指向window
这里只举例子,就不多解释了
1.普通函数调
非严格模式:
<script>
function a() {
console.log('结果是---',this);
}
a();
</script>
严格模式下:
<script>
"use strict"
function a() {
console.log('结果是---',this);
}
a();
</script>
2.函数作为对象的方法调用
<script>
var a = {
name:'test',
test:function(){
console.log('结果是---', this);
}
}
a.test()
</script>
3.使用new 构造函数创建对象
<script>
function Person(name) {
this.name = name;
}
var jack = new Person("Jack");
console.log('结果是---', jack.name);
</script>
4.上下文的方式调用(call | apply)
<script>
var obj1 = {
name : "obj1",
showName : function () {
console.log('结果是---',this);
}
};
var obj2 = {
name : "obj2"
};
obj1.showName("憨厚","厚道");
obj1.showName.call(obj2,"狡猾","灵活");
obj1.showName.apply(obj2,["智商高","情商高"]);
</script>
5.定时器中
<script>
var time1 = setInterval(function () {
console.log('time1结果是---',this);
},1000)
var time2 = setTimeout(function () {
console.log('time2结果是---',this);
clearInterval(time1);
clearTimeout(time2)
},2000)
</script>
在阮一峰老师《# ECMAScript 6 入门》中提到的:
箭头函数有几个使用注意点:
(1)函数体内的this对象,就是定义时所在的对象,而不是使用时所在的对象。
(2)不可以当作构造函数,也就是说,不可以使用new命令,否则会抛出一个错误。
(3)不可以使用arguments对象,该对象在函数体内不存在。如果要用,可以用 rest 参数代替。
(4)不可以使用yield命令,因此箭头函数不能用作 Generator 函数。
上面四点中,第一点尤其值得注意。this对象的指向是可变的,但是在箭头函数中,它是固定的。
怎么理解呢,举个例子
<body>
<button>点击</button>
<script src="http://apps.bdimg.com/libs/jquery/1.10.2/jquery.min.js"></script>
<script>
$('button').click(()=> {
console.log(obj);
})
var obj = () => {
console.log(this)
}
</script>
</body>
这个容易理解,点击时调用了obj,而obj当中的this就指向了obj本身,跟ES5一样。
那么,将上面js中的obj对象改一下,
var obj = {
test: function () {
setTimeout(() => {
console.log(this)
});
}
}
可以看到,setTimeout里的this依然指向obj,而不是指向window,这就是箭头函数里this指向要注意的地方了。
箭头函数当中,是没有自己的this的,它的this是继承而来;默认指向在定义它时,它所处的对象(宿主对象)。
上个例子中,this的宿主对象是obj,那么不管在obj里使用多少次箭头函数,箭头函数中的this都会指向obj,换句话说,在obj中,this的指向是固定的,固定指向了obj。
<body>
<button>点击</button>
<script src="http://apps.bdimg.com/libs/jquery/1.10.2/jquery.min.js"></script>
<script>
$('button').click(() => {
console.log(obj);
})
var obj = {
test: function () {
setTimeout(() => {
console.log(this)
});
},
test1: function () {
setTimeout(() => {
console.log(this)
})
},
test2: function () {
setTimeout(() => {
console.log(this)
})
}
}
</script>
</body>
如果把obj去掉,this会指向哪里呢?
<body>
<button>点击</button>
<script src="http://apps.bdimg.com/libs/jquery/1.10.2/jquery.min.js"></script>
<script>
$('button').click(() => {
console.log(this);
})
</script>
</body>
可以看到,在没有定义的情况下,箭头函数中的this是指向window而不是执行对象button。
可以把这种情况转换成普通函数的情况就容易理解了:在普通函数中,this指向它的直接调用者;如果找不到直接调用者,则是window。
对于箭头函数来说,本身没有this,但是没有调用的宿主对象,那么这个时候只能继续向上指向,最后指向到window。