Javascript中的this指向问题总结

96 阅读3分钟

Javascript中的this指向问题总结

记住两点

  1. this的指向永远是一个对象
  2. this的指向完全取决于函数的调用位置

总的来说就是谁调用就指向谁

普通函数中的this指向

首先普通函数的this分两种情况,严格模式和非严格模式

//严格模式
function test(){
    console.log(this)
}
test() //undefined
window.test()//window

//非严格模式
function test(){
    console.log(this)
}
test() //window
window.test()//window

对象中的this指向

原则:对象中谁调用就指向谁

const Person={
    name:'张三',
    skill:function(){
        name:'李四',
        console.log(this.name)
    },
    person2:{
        name:'王五',
        skill:function(){
            name:'老六',
            console.log(this.name)
        }
    }
}

Person.skill()//张三
Person.person2.skill()//王五
  1. 对象中谁调用了函数this就指向谁
  2. 多层嵌套对象,内部方法的this就指向离被调函数最近的对象

构造函数中的this指向

构造函数中的this指向创建的实例对象

function Person(name,sex,age){
    this.name=name;
    this.sex=sex;
    this.age=age;
}
var messgae=new Person('张三','男',18);
console.log(message.name);//张三
console.log(message.sex);//男
console.log(message.age);//18

箭头函数中的this指向

箭头函数中没有this,它会绑定最近的非箭头函数作用域的this。首先从它的父级作用域找,如果父级作用域还是箭头函数,就再往上找,直到找到this指向

var test=()=>{console.log(this)}
var obj={test:test}
//等价于
    //obj={
    //    test:()=>{
    //        console.log(this)
    //    }
    //}

test()//window
obj.test()//winow

第一个直接调用test相当于window.test()因此this指向window
第二个test是箭头函数往上一步找作用域找到了obj,obj是对象不是箭头函数则this绑定到了obj上,window调用obj,所以this的指向就指向了window相当于window.obj.test()

特殊函数的this指向(定时器)

const test={
    count:function(delay=1000){
        setTimeout(function(){
            console.log(this)
        },delay)
    }
}
test.count()//window

当定时器的回调函数用匿名函数的时候this指向window

使用箭头函数可以保全this的作用域

const tahoe={
    hills:['Rose','Tallac','Silver'],
    print:function(delay=1000){
        setTimeout(()=>{
            console.log(this.hills.join(","));
        },delay);
    }
}
tahoe.print();//Rose,Tallac,Silver

//报错一:
const tahoe={
    hills:['Rose','Tallac','Silver'],
    print:function(delay=1000){
        setTimeout(function(){
            console.log(this.hills.join(","));
        },delay);
    }
}
tahoe.print();//Uncaught TypeError:cannot read property 'join' of undefined

//报错二:
const tahoe={
    hills:['Rose','Tallac','Silver'],
    print:(delay = 1000)=>{
        setTimeout(()=>{
            console.log(this.hills.join(","));
        },delay);
    }
}
tahoe.print();//Uncaught TypeError:cannot read property 'join' of undefined

使用了箭头函数this的指向setTimeout的上一层作用域function,然后是对象tahoe调用了print方法,所以这里的this指向tahoe对象,因此对象上有hills这个数组属性。要是setTimeout回调函数使用匿名函数,这个的代码就会报错,因为window上没有hills这个数组。要是print方法使用的是箭头函数又会报错,因为继续往上找一层作用域,然后this的指向重新指向window,window上没有hills这个数组。

改变this指向(apply、call、bind)

apply和call

  • apply('你想指定的上下文',[存放函数传入的参数(数组形式)])
  • call('你想指定的上下文',传入函数的第一个参数,传入函数的第二个参数,...)
var name='张三'
var person={
    name:'李四'
}
function showName(info1,info2){
    console.log(this.name,info1,info2)
}
showName('hello',18)//张三 hello 18
showName.apply(person,['hello',18])//李四 hello 18
showName.call(person,'hello',18)//李四 hello 18

bind

bind和call的语法一样,只是call会立即执行函数,而bind会返回一个新的函数不会立即执行

var name='张三'
var person={
    name:'李四'
}
function showName(info1,info2){
    console.log(this.name,info1,info2)
}
showName('hello',18)//张三 hello 18
var newShowName=showName.bind(person)//并不会执行,而是返回了一个新函数newShowName
newShowName('hello',18)//李四 hello 18

//var newShowName=showName.bind(person,'haha',36)//并不会执行,而是返回了一个新函数newShowName
//newShowName('hello',18)//李四 haha 36
//函数新传入的参数会拼接在后面,这里一共四个参数传入('haha',36,'hello',18),所以只输出了前两个参数