this指向的深入解析

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/strongbill/article/details/85297874

在面试题中,老是喜欢给一段代码,然后问这里的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);//这两种写法都可以

猜你喜欢

转载自blog.csdn.net/strongbill/article/details/85297874