this的指向

40 阅读4分钟

this是在什么时候确定下来的?

首先必须要说的是,this和作用域不一样,作用域是声明的时候就确定下来的,而this指向是在函数执行的时候才能确定是谁,this的指向最终指向那个调用它的对象

例子1

function a(){
    var user = "qm";
    console.log(this.user); //undefined
    console.log(this); //Window 严格模式下是undefined
}
a();

a是全局函数,this指向是window,严格模式下是undefined

例子2

 setTimeout(function () {
        console.log(this); //window setTimeout比较奇怪,默认绑定严格模式下竟然不是undefined
    });
    
    btn.onclick = function(){ // 这是一个函数A
    setTimeout(function(){ // 这是一个函数B
        console.log(this); //window
    },0)
}
btn.onclick();

对于setTimeout是一个特例,this指向指向window

例子3

var o = {
    user:"qm,
    fn:function(){
        console.log(this.user);  //qm
        console.log(this) // o
    }
}
o.fn();

这里的this指向是对象o,因为你调用fn对通过o.fn()执行的,那自然指向是对象o。再次强调一下,this的指向只有调用的时候才能决定,谁调用就指向谁。

例子4

var o = {
    a:10,
    b:{
        a:12,
        fn:function(){
            console.log(this.a); //12
            console.log(this); // b
        }
    }
}
o.b.fn();



var o = {
    a:10,
    b:{
        // a:12,
        fn:function(){
            console.log(this.a); //undefined
            console.log(this); // b
        }
    }
}
o.b.fn();

就算对象嵌套多层,this指向也是他上一级对象,因为是b对象调用的,所以this指向指向b

例子5

var o = {
    a:10,
    b:{
        a:12,
        fn:function(){
            console.log(this.a); //undefined
            console.log(this); //window
        }
    }
}
var j = o.b.fn;
j();

这里指向还是window,是不是有些懵逼?其实是因为没有理解一句话

this永远指向的是最后调用它的对象,也就是看它执行的时候谁调用的,这是是把变量赋值给了j,最后执行的是j,所以最后this指向是window

例子6

const obj1 = {
        name:'joy',
        getName(){
            console.log(this); //obj
            console.log(this.name); //joy
        }
    };

    const obj2 = {
        name:'sam',
        friend:obj1
    };

    const obj3 = {
        name: 'jam',
        friend:obj2
    };

    obj3.friend.friend.getName()  //obj joy本质上还是obj1调用的
const obj1 = {
        name:'joy',
        getName(){
            console.log(this); 
            console.log(this.name); 
        }
    };

    const obj2 = {
        name:'sam',
        getName:obj1.getName
    };

    obj2.getName()  //obj2 sam

这是一些链式调用

例子7 (构造函数版this)

function Fn(){
    this.user = "qm";
    console.log(this) // 此处this 分别指向Fn的实例对象a1 a2
}
var a1= new Fn();
var a2=new Fn();
console.log(a.user); //qm

当this碰到return时

function Fn()  
{  
    this.user = 'qm';  
    return {};  
}
var a = new Fn();  
console.log(a.user); //undefined

再看一个

function Fn()  
{  
    this.user = 'qm';  
    return function(){};
}
var a = new Fn();  
console.log(a.user); //undefined

再来

function Fn()  
{  
    this.user = 'qm';  
    return 1;
}
var a = new Fn();  
console.log(a.user); //qm



function Fn()  
{  
    this.user = 'qm';  
    return undefined;
}
var a = new Fn();  
console.log(a.user); //qm

什么意思呢?

如果返回值是一个对象,那么this指向就是那个返回的对象,如果返回值不是一个对象,那么this还是指向函数的实例

再看

function Fn()  
{  
    this.user = 'qm';  
    return undefined;
}
var a = new Fn();  
console.log(a); //fn {user: "qm}

还有一点就是null也是对象,但是在这里this指向还是函数实例,因为null比较特殊

function Fn()  
{  
    this.user = 'qm';  
    return null;
}
var a = new Fn();  
console.log(a.user); //qm

new的原理,就是新建一个对象实例,this指向这个空对象,执行构造函数方法,属性和方法被添加到this引用的对象中

例子8

<body>
    <button id="btn">hh</button>
<script>
    var oBtn = document.getElementById("btn");
    oBtn.onclick = function() {
        console.log(this); // btn
    }
</script>
</body>

通过绑定事件的方法,此时this指向绑定事件的对象

例子9(想要改变setTimeout的this指向)

btn.onclick = function(){
    var self = this; //使用变量保存this
 
    function fn(){  //将代码写在一个函数fn中
        console.log(this);
    }

    setTimeout(function(){
        fn.call(self); //强行指定this为self对象
    },0)
}
btn.onclick();
/*
  call方法的作用,是调用函数,同时指定this可以代表谁
  例如 fn.call(obj)
  意思就是 调用函数fn,并且this指向obj对象
*/



btn.onclick = function(){
    var self = this; //使用变量保存this
 
    function fn(){  //将代码写在一个函数fn中
        console.log(this);
    }

    setTimeout(function(){
        fn.apply(self); //使用apply方法调用函数,强行指定this为self对象
    },0)
}
btn.onclick();
/*
  apply方法的作用,是调用函数,同时指定this可以代表谁
  例如 fn.apply(obj)
  意思就是 调用函数fn,并且this指向obj对象
*/
btn.onclick = function(){
    setTimeout(function(){
        console.log(this);
    }.bind(this), 0 )
    //使用bind方法,将定时器函数的this强行绑定为事件函数的this
}
btn.onclick();
/*
  bind方法的作用,是绑定函数的this,同时返回绑定后的新函数
  例如 
  var fb = fn.bind(obj);
  window.fb();
  无论谁调用fb函数, 函数的this都会指向obj
*/

利用call,apply,bind改变this指向

如何判断箭头函数的this?

因为箭头函数不具备自己的this,所以非常简单,只要假装它不存在,就想这样,这下this指向就很清晰了

image

2.箭头函数可以用call来改变this指向吗?

不能!!试图改变箭头函数的this是徒劳的