this指向

this指向解析

几个月之前就想要写一些博客,记录本身的学习历程,但因为各类缘由,没能动工,2019的第一个月即将过去,今天终于下定决心抓住一月的尾巴,勤奋一把,激励本身在2019能有所收获。因此这第一篇,就从面试常见的考点this指向开始吧。面试

总的来讲,咱们始终要牢记的一句话就是:this始终指向最终调用它的那个对象数组

1.直接做为一个函数被调用,this指向window

function demo () {
    var a = '这是第一个demo的a'
    console.log(this)
    console.log(this.a)
}
demo()
// window
// undefined
复制代码

为何此处this.a是undefined呢?由于咱们能够把demo当作window.demo,window对象并无a这个属性,因此是undefined。若是但愿打印出'这是第一个demo',能够将代码改成以下示例:bash

function demoUpdate () {
    this.a = '这是第一个demo的a'
    console.log(this)
    console.log(this.a)
}
demoUpdate()
// window
// 这是第一个demo的a
复制代码

2.做为对象的方法被调用,this指向这个对象

var obj = {
    a: '这是第二个demo的a',
    func: function () {
        console.log(this)
        console.log(this.a)
    }
}
obj.func()
// 指向obj
// 这是第二个demo
复制代码

3.做为构造函数被调用,this指向这个构造函数的实例对象

function Constructor () {
    var a = '这是第三个demo的a'
    this.a = '这是第三个demo的b'
    console.log(this)
    console.log(this.a)
}
var func = new Constructor()
// 指向Constructor的实例对象
// 这是第三个demo的b
复制代码

为何此处的this.a指向的倒是'这是第三个demo的b',而不是a呢?这就涉及到构造函数的继承问题了,这里用var a 声明的a在Constructor的实例对象,也就是func中实际上并不存在,只有this.a声明的这个a对象才被func对象继承,存在于func中,因此当打印this.a时,打印的就是'这是第三个demo的b'app

4.若是一个函数中有this,且这个函数中包含多个对象,this指向它的上一级对象,即最后调用它的那个对象

var obj = {
    a: '这是第四个demo的外层a',
    child: {
        a: '这是第四个demo的内层a',
        func: function () {
            console.log(this)
            console.log(this.a)
        }
    }
}
obj.child.func()
// 指向obj.child
// 这是第四个demo的内层a
复制代码

5.若是遇到return,若return的是一个对象,则this指向这个对象,若return的不是对象,则仍然指向这个函数的实例(null例外,虽然null是一个对象,但仍然指向对象的实例)

function Constructor () {
    this.a = '这是第五个demo的a'
    return {}
}
var b = new Constructor
console.log(b.a) //undefined
复制代码

由于此时b指向的是Constructor生成的实例对象,而这个对象是个空对象,没有a属性函数

function Constructor () {
    this.a = '这是第六个demo的a'
    return function () {}
}
var b = new Constructor
console.log(b.a)  // undefined,此时b指向的是Constructor的新的实例对象,也就是function () {}
复制代码

再看return的不是对象的状况学习

function Constructor () {
    this.a = '这是第七个demo的a'
    return 1
}
var b = new Constuctor
console.log(b.a)  // 这是第七个demo的a
复制代码

此时b指向的是新生成的Constructor的实例对象,这个实例对象的a属性即为:这是第七个demo的aui

function Constructor () {
    this.a = '这是第八个demo的a'
    return undefined
}
var b = new Constructor
console.log(b.a) // 这是第八个demo的a,理由同上
复制代码
function Constructor () {
        this.a = '这是第九个demo的a'
        return null
    }
    var b = new Constructor
    console.log(b.a) // 这是第九个demo的a
复制代码

改变this的指向

首先看一个没有改变this指向时的例子this

var obj = {
    a: '这是第十个demo的a',
    func1: function () {
        console.log(this.a)
    },
    func2: function () {
        setTimeout( function () {
            this.func1()
        }, 1000)
    }
}
obj.func2() // this.func1 is not a function 
复制代码

为何此处报错而没有打印‘这是第十个demo的a’呢?由于当调用obj.func2时,func2中的setTimeout函数实质上是调用window对象的setTimeout函数,this指向window,而window对象没有func1这个属性,因此报错spa

1.使用箭头函数改变this的指向

箭头函数中没有this绑定,必须经过做用域链决定this的值,若是箭头函数被非箭头函数包含,则this指向最近的一层非箭头函数的this,不然,this为undefinedcode

var obj = {
    a: '这是第十一个demo的a',
    func1: function () {
        console.log(this.a)
    },
    func2: function () {
        setTimeout(() => {
            this.func1()
        }, 1000)
    }
}
obj.func2() // 这是第十一个demo的a
复制代码

2.在函数内部使用that = this改变this的指向

var obj = {
    a: '这是第十二个demo的a',
    func1: function () {
        console.log(this.a)
    },
    func2: function () {
        var that = this
        setTimeout(function() {
            that.func1()
        }, 1000)
    }
}
obj.func2() // 这是第十二个demo的a
复制代码

3.使用call,apply, bind改变this的指向

首先区分这三个函数的区别: call和apply改变this的指向后当即执行,而bind仅绑定this的指向,并不当即执行,返回改变this指向后的函数

call和bind的参数能够有多个,第一个参数为绑定的this的指向,后面的参数为传入函数的参数

apply只有两个参数,第一个参数为绑定的this的指向,第二个参数为包含传入函数的参数的数组

以上内容为我本身记录的知识点,若是后面有补充的,我会继续添加,此博客仅作记录知识点使用,如有幸被大佬们指点,不对的还烦请指正。

相关文章
相关标签/搜索