this指向的深入解析
在面试题中,老是喜欢给一段代码,然后问这里的this的到底指向谁,切记这里有一个坑,有些出题人出的题目原本就是错的,然后故意问你这里的this指向的是谁。
这里要明确指出,在函数定义的时候用到了this,这时是确定不了this的指向的,只有在函数执行的时候才能确定this到底指向谁,实际上this的最终指向的是那个调用它的对象,也可以说是函数运行时所在的环境对象。
5种this的常用方法
1. 纯粹的函数调用
这时全局性调用,其实在全局中定义的变量name和函数sayName( )都是挂载在全局对象window下面的
var name = 'mr3x';
function sayName(){
var name = 'bill';
console.log(this.name);
}
console.log(name); //mr3x
console.log(window.name); //mr3x
sayName(); //mr3x
window.sayName(); //mr3x
要注意严格模式的this,使用use strict有两种方式,一种是在脚本第一行写,作用于当前的脚本文件,一种是写在函数里面,作用于当前函数
function foo(){
console.log(this);
}
function bar(){
'use strict'; //使用严格模式
console.log(this);
}
foo(); //window
bar(); //undefined
2.对象的调用
函数作为某个对象的方法给调用的时候,指向的是上级对象
function sayName(){
console.log(this.name);
}
var person = {
name: 'mr3x',
sayName: sayName,
};
person.sayName(); //mr3x
下面这种情况和上面这种情况不是同一种情况,这里是将man指向了person.sayName这一个内存空间地址,还没有调用,真正的调用是man( ),然后这里又回到了纯粹的函数调用
var name = 'bill'
function sayName() {
console.log(this.name);
}
var person = {
name: 'mr3x',
sayName: sayName,
};
var man = person.sayName;
man(); //bill
切记,这里是指向的上级对象,看下面的例子,
var person = {
name: 'mr3x',
method: {
name: 'bill',
sayName: function(){
console.log(this.name); //bill
console.log(this); //person.method
}
}
};
person.method.sayName();
尽管这个函数是给最外层的对象所调用,但是this指向也只是指向它的上级对象
3.构造函数的调用
构造函数就是通过这个函数生成一个新的对象。然后这个时候的this就指向这个新的对象
var name = 'bill'
function Person(){
this.name = 'mr3x';
}
var obj = new Person();
console.log(obj.name); //mr3x
下面的是特殊情况,一般不这么写,但面试题有时就是喜欢出些乱七八糟的。当遇到关键字return的时候
我们先是return一个空对象的时候,返回的是undefined
var name = 'bill'
function Person(){
this.name = 'mr3x';
return {}
}
var obj = new Person();
console.log(obj.name); //undefined
那我们return 一个数值的时候,返回的竟然是mr3x
var name = 'bill'
function Person(){
this.name = 'mr3x';
return 1;
}
var obj = new Person();
console.log(obj.name); //mr3x
那我们return 一个undefined的时候,返回的竟然是mr3x
var name = 'bill'
function Person(){
this.name = 'mr3x';
return undefined;
}
var obj = new Person();
console.log(obj.name); //mr3x
在说为什么之前,我们先说一下null和undefined的一些基础知识
typeof null //object
typeof undefined //undefined
null == undefined //true
null === undefined //false
其实,如果return回去的是一个对象(如函数),那么this就指向这个对象,如果不是对象那么就指向new 出来的实例
但还有一个特殊的家伙就是null,这货虽然是对象,可他还是指向new 出来的实例
var name = 'bill'
function Person(){
this.name = 'mr3x';
return null;
}
var obj = new Person();
console.log(obj.name); //mr3x
4.定时器的情况
setInterval和setTimeout中的回调函数中的this指向的是window
var name = 'mr3x'
var person = {
name: 'bill',
sayName: function(){
setInterval(function(){
console.log(this.name);
}, 1000);
}
}
person.sayName(); //mr3x
5.事件绑定的情况
这个时候this指向绑定事件的对象
<body>
<button id="btn">click me</button>
<script>
var btn = document.querySelector('#btn');
btn.onclick = function(){
console.log(this); //button#btn
}
</script>
</body>
3种修改this指向的方法
1.call()方法
var obj = {
name: 'mr3x'
}
function sayName(a, b){
var name = 'bill';
console.log(a, b); // 10 20
console.log(this.name); // mr3x
}
sayName.call(obj, 10, 20);
sayName.call(obj, 10, 20)这句的意思是把sayName中的this指向obj,后面的10和20是要传入的参数
2.apply()方法
call()方法和apply()方法本质上没有什么区别,只是第二个参数传入的时候不一样而已,apply的参数传入是用数组的
var obj = {
name: 'mr3x'
}
function sayName(a, b){
var name = 'bill';
console.log(a, b); //10 20
console.log(this.name); //mr3x
}
sayName.apply(obj, [10,20]);
3.bind()方法
bind()方法返回的是一个新的函数,也叫做绑定函数,与被调用的函数拥有相同的函数体。
var obj = {
name: 'mr3x'
}
function sayName(a, b){
var name = 'bill';
console.log(a, b); //10 20
console.log(this.name); //mr3x
}
sayName.bind(obj, 10, 20)();
sayName.bind(obj)(10, 20);//这两种写法都可以