JS中常见的this指向

319 阅读5分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第9天,点击查看活动详情

this

概要

1.this是什么?

  • 任何函数本质上都是通过对象来调用,如果没有直接指定对象,那就是window
  • 所有函数的内部都有一个变量this
  • this就是调用当前这个函数的对象
    2.如何确定this的值?
  • test() : this是window
  • p.test() : this是p
  • new test() : this是新创建的对象
  • p.call(obj) : this是obj(apply、bind这些可以改变this指向)
    例题:
        function Person(color) {
            console.log(this);
            this.color = color;
            this.getColor = function () {
                console.log(this);
                return this.color;
            };
            this.setColor = function (color) {
                console.log(this);
                this.color = color;
            };
        };

Person('red'); this是谁? 👉 window

var p = new Person('yellow');👉 this是谁? 其实和p没关联,this指向的是Person对象,只是new 了一个对象后,让p指向Person对象,所以this是p也没错

p.getColor(); this是谁?👉 p

var obj = {}; p.setColor.call(obj, "black"); this是谁?👉 obj

var test = p.setColor; test(); this是谁?👇
首先p.setColor得到这个函数,然后赋值给test变量,那么这就是一个函数表达式,然后又因为test是全局变量嘛,全局变量会自动成为window对象的成员,这句代码也就相当于window.test(),所以是window调用的,指向的是window

      👇function fun1() {
            function fun2() {
                console.log(this);
            }
            fun2();
        }

        fun1();👇👇👇

this还是window,因为所有JavaScript全局对象、函数以及变量均自动成为window对象的成员,fun2()也就等同于window.fn2()

常见的this指向

核心:this指向问题 一般情况下this的最终指向的是那个调用它的对象

1.全局作用域或者普通函数中this指向全局对象window(注意定时器里面的this指向window)
见如下代码:

        console.log(this); //window

        function fn() {
            console.log(this); //window
        }
        fn(); //因为这是简写,完整的是window.fn(),所以是指向window

        window.setTimeout(function () {
            console.log(this); //也是指向window
        }, 1000);

2.方法调用中谁调用this就指向谁
见以下代码

        var o = {
            sayHi: function () {
                console.log(this); //this指向o这个对象
            }
        }
        o.sayHi();
        var btn = document.querySelector('button');
        btn.onclick = function () {
            console.log(this); //this指向这个button按钮。监听事件方法注册事件也是一样的
        }

3.构造函数中,this指向构造函数的实例

        function Fun() {
            console.log(this);
        }
        var fun = new Fun();

之前我们讨论过new的执行过程,new先划分了一块空间,然后构造函数中的this全部指向这个空间,而这个对象实例化后赋值给了fun变量,所以this指向的是这个变量fun。

其他补充

window

  • 所有浏览器都支持window对象。他表示浏览器窗口。
  • 所有JavaScript全局对象、函数以及变量均自动成为window对象的成员。
  • 全局变量是window对象的属性
  • 全局函数是window对象的方法 而且window是默认特性,可以省略不写

        function fun3() {
            console.log(this);
        }

关于以上代码,解析器在调用函数时,每次都会向函数内部传递一个隐含的参数,这个隐含的参数就是this,这也就是为什么能直接log this的原因0 0
this指向的是一个对象,这个对象我们称为 函数执行的 上下文对象
根据函数的调用方式不同,this会指向不同的对象(谁调用指向谁)

  • 以函数形式调用时,this指向永远是window
  • 以方法形式调用时,this指向调用方法的对象

严格模式中的this

严格模式下this指向问题
① 以前在全局作用域函数中的this指向window对象
② 严格模式下全局作用域中函数中的this是undefined
③ 以前构造函数时不加new也可以调用,当普通函数,this指向全局对象
比如

function Star(){
            this.sex = '男';
        }

Star();直接调用,相当于window调用,this是window,也就为window添加了个sex属性

④ 严格模式下,如果构造函数不加new调用,this会报错
⑤ new 实例化的构造函数指向创建的对象实例
⑥ 定时器中的this指向还是window
⑦ 事件、对象还是指向调用者

ES6箭头函数的this指向

ES6中的this,是静态的, this 始终指向函数声明时所在作用域下的this的值

        function getName() {
            console.log(this.name);
        }👇

普通函数在全局作用域下自动成为window的方法,this指向window

    let getName2 = () => {
        console.log(this.name);
    }👇

上面箭头函数是全局作用域下声明的,所以this指向的是window,而箭头函数中的this是静态的,声明时指向的是window,后面不管怎么样this都指向window

        //设置window对象的name属性
        window.name = '你好呀';
        const school = {
            name: "我很好"
        }

直接调用
getName(); //你好呀
getName2(); //你好呀
call方法调用
getName.call(school); // "我很好"
getName2.call(school); // "你好呀",getName2是个箭头函数,this是静态的,哪怕现在是让它临时成为school对象的方法让school来调用,this指向还是window


其他例题:
以前是在外面保存this的值到变量里面,在放到定时器中使用,现在利用箭头函数中this的静态特性,可以像下面代码一样写

    ad.addEventListener('click', function () { //监听事件函数的this指向的是ad
            setTimeout(() => {
                this.style.background = 'pink';
            }, 2000);
        })

注意! 箭头函数没有自己的this,它的this指向父级的this也就是函数的this,而这个函数的this是谁调用函数就指向谁,所以箭头函数的this也是ad
总结:

  • 箭头函数适合与this无关的回调。定时器、数组的方法回调
  • 箭头函数不适合与this有关的回调。事件回调,对象的方法(只说不适合,没说不能,某些情况是可以做为对象的方法的)

总之,箭头函数中是没有this的!在箭头函数里边写的this,它会沿着作用域去找外边的this