探究JavaScript中的this为啥东指西指

js中的this可谓是花样百出,在不同的环境、不同的作用下表现是不同的,下面我们就来探究一下js中this的用法和指向问题

1.首先从最简单的开始说,普通的函数中this的指向

function test() {
    this.a = 1;
    console.log(this);
    console.log(this.a);
}

test();
复制代码

结果

Window
1
复制代码

可以看出this是指向window的,函数中this.a 相当于window.a

但如果在js的严格模式下,可就不一样了,我们在函数中加一段”use strict”


function test() {
    'use strict';
    console.log(this);
}

test();
复制代码

结果

undefined
复制代码

结果为undefined 所以说在严格模式下,普通函数执行的时候内部this不指向谁

2.对象中的方法this指向

var obj = {
    a: 1,
    test: function () {
        console.log(this);
        console.log(this.a);
    }
}
obj.test();
复制代码

结果

{a: 1, test: ƒ}
1
复制代码

那我们就明确了对象里面的方法是可以通过this访问到对象本身的,从而就可以通过this.** 访问到对象里面的属性和方法

3.构造函数中this的指向

function Test(a) {
    this.a = a;
    console.log(this.a);
    console.log(window.a);
}

var test = new Test(1);
复制代码

结果

1
undefined
复制代码

window.a为undefined,说明在构造函数在被实例化之后,this不会指向window,我们在构造函数中加一句console.log(this)
结果

{a: 1}
复制代码

由此可以看构造函数在被实例化之后,其中this指向被实例化出来的对象
那么构造函数原型上的方法this指向什么呢?
我们在原型是定义一个方法

Test.prototype.say = function () {
    console.log(this.a); // 1
}
test.say();
复制代码

能正常的打印出 a 的值,也就证明了一点:原型上方法内部的this依然指向构造函数实例化出来的对象

4.事件处理函数中this的指向

在页面中创建一个按钮

<button id="btn">CLICK</button>
复制代码

当他点击的时候,给它绑定一个事件处理函数

var oBtn = document.querySelector('#btn');
oBtn.addEventListener('click', function () {
    console.log(this)
}) 
复制代码

结果

<button id="btn">CLICk</button>
复制代码

由此得出事件处理函数内部的this指向绑定元素的本身

5.call/apply/bind 改变this的指向

call:函数名.call(this, arg1, arg2, …),第一个参数用来指定函数内部this的指向,后面的参数是函数执行时所需要的实参

var obj = {
    a: 1,
    b: 2
}

function test(c, d) {
    console.log(c + ',' + d);
    console.log(this.a);
}

test.call(obj, 10, 100);
复制代码

结果:

10, 100
1
复制代码

apply:函数名.call(this, [arg1, arg2, …]),与call不同的是把实参放到一个数组中传入

var obj = {
    a: 1,
    b: 2
}

function test(c, d) {
    console.log(c + ',' + d);
    console.log(this.a);
}

test.apply(obj, [10, 100]);
复制代码

结果:

10, 100
1
复制代码

bind:bind用法和call一样,只是他不像call/apply会立即执行,而是返回一个新的函数

var obj = {
    a: 1,
    b: 2
}

function test(c, d) {
    console.log(c + ',' + d);
    console.log(this.a);
}

const _test = test.bind(obj, 10, 100);
_test();
复制代码

结果:

10, 100
1
复制代码

6.箭头函数中this的指向

上面我们说到普通函数可以通过call/apply/bind改变this的指向 ,但是如果在es6的箭头函数中,是否还能像上面一样改变this的指向呢?不妨来试一下

var obj = {
    a: 1,
    b: 2
}
var a = 100

const test = () => {
    console.log(this.a);
}
test.call(obj);
复制代码

结果:

100
复制代码

发现并没有打印出 1 ,所有得出一个结论:箭头函数忽略任何形式的this指向的改变。
那么箭头函数中的this到底指向什么呢?我们先看几个例子之后再进行总结:

  • 在一个对象中添加一个方法,这个方法是一个箭头函数
var obj = {
    a: 1,
    test: () => {
        console.log(this)
    }
}
obj.test();
复制代码

结果

Window // 指向 window
复制代码

由此可以知道箭头函数中的this不是谁绑定就指向谁

  • 在对象的一个方法中再定义一个箭头函数,并执行
var obj = {
    a: 1,
    test: function () {
        var t = () => {
            console.log(this)
        }
        t();
    }
}
obj.test();
复制代码

结果

{a: 1, test: ƒ} // 指向 obj
复制代码
  • 对象的方法为一个箭头函数
var obj = {
    a: 1,
    test: () => {
        var t = () => {
            console.log(this)
        }
        t();
    }
}
obj.test();
复制代码

结果

Window // 指向 window
复制代码
  • 在闭包函数中定义一个箭头函数
var obj = {
    a: 1,
    test: function () {
        var t1 = function () {
            var t2 = () => {
                console.log(this);
            }
            t2();
        }
        t1();
    }
}
obj.test();
复制代码

结果

Window // 指向 window
复制代码
  • 再看一个例子
var obj = {
    a: 1,
    test: function () {
        var t1 = () => {
            var t2 = () => {
                console.log(this);
            }
            t2();
        }
        t1();
    }
}
obj.test();
复制代码

结果

{a: 1, test: ƒ} // 指向 obj
复制代码

由以上几个例子我们可以得出结论:箭头函数的this指向外层作用域的this指向,但是外层不能是箭头函数,也就是说箭头函数this的指向就是外层非箭头函数this的指向


所以我们在分析this的指向的时,不能片面的认为被谁调用就指向谁,还要根据其所处的环境进行进一步分析

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享