js 箭头函数和普通函数的区别和this指向看这篇就够了

this指向问题是个老问题了,网上的教程很多都是相互copy的,让萌新一脸蒙,这里简单总结下,保证一次性搞懂。

首先,这里有个问题是js严格模式非严格模式,严格模式和非严格模式下this指向稍微有点区别,主要就是全局作用域中普通函数中的this指向问题,严格模式下是指向undefined的,非严格模式下是指向window。

image.png

现在一般用的都是严格模式,比如vue中就是这样。

image.png

本文案例都是在严格模式下。

话入正题:箭头函数和普通函数有什么区别?

箭头函数没有arguments参数、无法作为构造函数,不能被new、this取决于上下文,本身没有this、使用call,apply等无法改变this指向。
而上面箭头函数不能做的普通函数都可以,其中普通函数的this指向调用方。

普通函数this指向?

答:普通函数的this指向调用方。

eg1:

image.png

首先这两种写法都是一样的,这里 a.say是对象a在调用,因为普通函数的this指向调用方,因此这里的this指向a

eg2:我们再来验证下:

image.png

这里我们将a.say的方法引用赋值给了b,然后用window.b调用,因此这里的this.namethis指向window

箭头函数this指向?

答:箭头函数本身没有this,this取决于定义时的上下文。也就是说箭头函数中的this指向的是定义时的this,而不是执行时候的this。

eg1:

image.png

这里say方法是箭头函数,在定义时a对象内是没有this的,当前this指向window.。window.b()虽然最后打印的是全局name,但是实际上是和调用方无关的,this是在定义的时候就确定了。

eg2:

image.png

这里箭头函数定义在函数内部,若当做普通函数直接调用,thisundefined若当做构造函数实例化this指向构造函数所创建的对象实例。
有的同学就想,哎呀?不是一开始就确定了this吗,怎么值还不一样诶?注意,这里当做构造函数使用相当于把它当做了,性质都不一样,this不一样完全是可以理解的。

还有一点要注意,这里是用的new 一个实例的方式调用的,在严格模式下构造函数不加new直接调用,因为thisundefined,this.name = xxxx 会报错,如下:

image.png

eg3:

image.png

这个例子出自这篇文章,具有误导性,但是理解了上面eg2这个例子你就明白了。这里person当做构造函数在使用,函数内getval是定义在构造函数内部的箭头函数,因为对象o在定义时是没有this的,因此getval内的this是构造函数的this,也就是指向构造函数所创建的对象实例。但是,person并没有返回这个this,该构造函数返回的是另一个对象o,但无论是返回的什么,getvalthis在定义时就确定了,那就是构造函数内的this

下面是测试使用的代码,方便大家测试:

    // ----------------- 分割线 ---------------------
    "use strict"
    window.name = '这是全局定义的name'
    var a = {
        name: '11',
        say(){
            console.log(this.name)
        }
    }
    a.say()

    // ----------------- 分割线 ---------------------
    "use strict"
    window.name = '这是全局定义的name'
    var a = {
        name: '11',
        say(){
            console.log(this.name)
        }
    }
    var b = a.say
    window.b()

    // ----------------- 分割线 ---------------------
    "use strict"
    window.name = '这是全局定义的name'
    var a = {
        name: '11',
        say: () => {
            console.log(this.name)
        }
    }
    a.say()
    var b = a.say
    window.b()

    // ----------------- 分割线 ---------------------
    "use strict"
    var fn = function () {
        this.name = '这是函数内定义的name'
        console.log(this)
        var a = {
            name: '11',
            say: () => {
                console.log(this)
            }
        }
        a.say()
    }
    var b = new fn()
    //    fn()

    // ----------------- 分割线 ---------------------
    "use strict"
    function person(fg) {
        this.name = '这是person内部'
        let o = new Object()
        o.flag = fg
        o.getval = () => {
            console.log(this)
        }
        return o
    }

    let pp = new person('251')
    pp.getval()

进阶:注意this指向改变问题

    "use strict"
    var obj = {
        func() {
            console.log('-----', this)
            function fn() {
                console.log('func', this)
            }

            fn()
        },
        func1() {
            console.log('-----', this)
            setTimeout(function () {
                console.log('func1', this);
            })
        },
        func2() {
            console.log('-----', this)
            setTimeout(() => {
                console.log('func2', this);
            })
        }
    }
    obj.func();
    obj.func1();
    obj.func2();
image.png

若对你有帮助,请点个赞吧,谢谢支持!

本文地址:https://www.jianshu.com/p/cdf9e4f6312b,转载请注明出处,谢谢。

参考:
https://blog.csdn.net/m0_61843874/article/details/123247934
https://blog.csdn.net/tanzhou123/article/details/105919159?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522165577960616782388095394%2522%252C%2522scm%2522%253A%252220140713.130102334..%2522%257D&request_id=165577960616782388095394&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2allbaidu_landing_v2~default-1-105919159-null-null.142v19control,157v15new_3&utm_term=%E7%AE%AD%E5%A4%B4%E5%87%BD%E6%95%B0%E7%9A%84this%E6%8C%87%E5%90%91+%E9%98%AE%E4%B8%80%E5%B3%B0&spm=1018.2226.3001.4187

你可能感兴趣的:(js 箭头函数和普通函数的区别和this指向看这篇就够了)