this指向和改变this指向

106 阅读3分钟

确定 this 的指向

先搞明白一个很重要的概念 —— this 的值是在执行的时候才能确认,定义的时候不能确认! 为什么呢 —— 因为 this 是执行上下文环境的一部分,而执行上下文需要在代码执行之前确定,而不是定义的时候。看如下例子:

// 情况1
function foo() {
  console.log(this.a) //1
}
var a = 1
foo()
​
​
​
// 情况2
function fn(){
  console.log(this);
}
var obj={fn:fn};
obj.fn(); //this->obj// 情况3 构造函数
function CreateJsPerson(name,age){
//this是当前类的一个实例p1
this.name=name; //=>p1.name=name
this.age=age; //=>p1.age=age
}
var p1=new CreateJsPerson("海牙",18);
​

//情况4 
var obj = {
    name:'海牙',
    showName:function(){
        console.log(this.name); // 海牙 this => obj
        (function(){
            console.log(this.name); //undefined this=>window
        })();
    }
}
obj.showName();


window.showName();
//报错 showName不是函数 
//window.showName =>undefind()=> 不是一个函数
</script>
    
//后续的点击事件 第五种情况
var oBtn = document.querySelector('#btn');
oBtn.onclick = function(e){
    console.log(e)
    this.value = '不要点我';
    //回调函数中的this指向 触发事件的对象
    //this=>oBtn 
}

接下来我们逐一解释上面几种情况

  • 对于直接调用 foo 来说,不管 foo 函数被放在了什么地方,this 一定是 window
  • 对于 obj.foo() 来说,我们只需要记住,谁调用了函数, this指向谁,所以在这个场景下 foo 函数中的 this 就是 obj 对象
  • 在构造函数模式中,类中(函数体中)出现的 this.xxx=xxx 中的 this 是当前类的一个实例
  • IIFE匿名函数自调用时 因为没有明确调用主体 this指向 window。
  • 定时器中的this 指向window
  • 箭头函数没有this

2019-03-19-01.png

call()

call() 方法的第一个参数必须是指定的对象,然后方法的原参数,挨个放在后面。 (1)第一个参数:传入该函数this执行的对象,传入什么强制指向什么; (2)第二个参数开始:将原函数的参数往后顺延一位

直接调用函数 可以实现继承

function uname(a,b) {
        console.log(this)
        console.log(a+b)
    }
    var o = {
        name: 'Herry'
}
uname.call(o,2,3) 
//输出对象o 和 5
//第一个参数 也可以传字符串等

继承

// 实现继承
    function Father(uname,uage,usex) {
        this.uname = uname;
        this.uage = uage;
        this.usex = usex;
    }
    function Son(uname,uage,usex) {
        Father.call(this,uname,uage,usex)
    }
    var son = new Son('Potter',18,'男')
    console.log(son);

apply()

apply() 方法的第一个参数是指定的对象,方法的原参数,统一放在第二个数组参数中。 (1)第一个参数:传入该函数this执行的对象,传入什么强制指向什么; (2)第二个参数开始:将原函数的参数放在一个数组

直接调用函数

// apply() 方法
function uname(a,b) {
        console.log(this)
        console.log(a+b)
    }
    var o = {
        name: 'Herry'
}
uname.apply(o,[2,3]) 
//输出对象o 和5
//第一个参数 也可以传字符串等

bind() (不会立即执行)

bind() 方法的用法和call()一样,不会调用原来函数,

需要注意的是:bind返回新的方法,需要重新调用

如果有的函数我们不需要立即调用,但是又想改变这个函数内部的this指向,此时用bind

// bind方法
// 与call(),apply()区别,不会调用原来函数,需要赋值后再调用一遍,调用函数与call()同
    function f(a,b) {
        console.log(this)
        console.log(a - b)
    }
    var j = {
        name: 'Kuper'
    }
    var h = f.bind(j,6,1);
    h();
​