JavaScript 中的 this 到底指向谁?

本文将详细介绍 “ JavaScript 中的 this 到底指向谁?”

this 指向问题核心就是把握如下两点:

1)this 指向的是对象

2)与函数或者方法如何声明的无关,而是要看这个函数或者方法最终被谁调用,谁最终调用这个函数或方法,那么这个函数或方法中的 this 就是谁

下面从简单到复杂的开始进行介绍。

普通函数中的 this

​
<script type="text/javascript">
    //声明式函数
    function showTime1(X) {
        console.log("showTime1+" + X, this);
    }

    //声明式函数
    function showTime2() {
        this.showTime1(130);
    }

    showTime1(110);
    window.showTime1(120);
    showTime2();
</script>

     showTime1(X)、showTime2() 作为声明式函数在编译的时候就已经绑定到了 Window 对象上,全局函数等同于给 Window 对象添加方法。

     所以第 13 行、第 14 行调用 showTime1(X) 函数本质一样,因为 showTime1(X) 被 Window 对象调用,所以 showTime1(X) 函数中的 this 就表示 Window 对象。

     第 15 行实在也同样是 Window 对象在调用 showTime2()函数,所以 showTime2() 中的 this 也就是 Windows 对象,而 Window 对象自然可以调用 showTime1(X)。运行结果如下:

对象方法中的 this

<script type="text/javascript">
        let jsonObj = {
            id: 9527,
            name: "华安",
            showAge: function () {
                console.log("年方18", this);
                console.log(this.id, this.name);
            }
        };
        jsonObj.showAge();
</script>

     jsonObj 是 Json 对象,第 10 行的 showAge() 方法由 jsonObj 对象调用,所以 showAge 方法中的 this 就表示 jsonObj 对象,运行结果如下:

复合案例

案例一:

    <script type="text/javascript">
        //声明式函数
        function showTime() {
            console.log(new Date().getTime(), this);
        }

        /**全局变量,也相当于为 window 对象添加的属性*/
        var id = 1001;
        var name = "宁王";

        //Json 对象
        let jsonObj = {
            id: 9527,
            name: "华安",
            showAge: function () {
                console.log("年方18", this);
                console.log(this.id, this.name);
            }
        };
        showTime = jsonObj.showAge;
        showTime();
    </script>

     关键在第 20 行,将 jsonObj 对象中的 showAge 函数的函数体赋值给了 showTime,所以第 21 行调用的肯定是第 15-18 行,已经知道第 21 行 showTime()本质就是 window.showTime(),也就是说方法其实是被 window 对象调用了,于是第 16-17 行中的 this 就表示 window 对象。运行结果如下:

案例二:

    <script type="text/javascript">
        //声明式函数
        function showTime() {
            console.log(new Date().getTime(), this);
        }

        /**全局变量,也相当于为 window 对象添加的属性*/
        var id = 1001;
        var name = "宁王";

        //Json 对象
        let jsonObj = {
            id: 9527,
            name: "华安",
            showAge: function () {
                console.log("年方18", this);
                console.log(this.id, this.name);
            }
        };

        jsonObj.showAge = showTime;
        jsonObj.showAge();
    </script>

      关键点同样在第 21 行,将 showTime 函数的函数体赋值给了 jsonObj 对象的 showAge 函数,所以第 22 行调用之后运行的肯定是第 3-5 行,而调用它的对象是  jsonObj 对象,所以第 4 行中的 this 就表示 jsonObj 对象。运行结果如下:

案例三:

    <script type="text/javascript">
        /**全局变量,也相当于为 window 对象添加的属性*/
        var id = 1001;
        var name = "宁王";

        //Json 对象
        let jsonObj = {
            id: 9527,
            name: "华安",
            tiger: {
                id: 8866,
                name: "江小白",
                showAge: function () {
                    console.log(this);
                    console.log(this.id, this.name);
                }
            }
        };
        jsonObj.tiger.showAge();
    </script>

          关键点在第 19 行,jsonObj 是 JSON 对象,它的属性 tiger 也是 JSON 对象,而真正调用 showAge() 函数的是 tiger 对象,所以第 15 行中的 this 表示 tiger 对象。运行结果如下:

构造函数中的 this

    <script type="text/javascript">
        /**ES5 中的类和普通函数写法类似,Tiger 就相当于一个构造器*/
        function Tiger() {
            this.id = 9527;
            this.name = "华安";
            console.log("构造器执行", this.id);

            this.showAge = function () {
                console.log(this.name + " 今年 28 岁.");
            }
        }

        let tiger = new Tiger();
        console.log(tiger);
        console.log(tiger.id, tiger.name);
        tiger.showAge();
    </script>

     new 关键字创建对象,构造器会执行,其中的 this 指向这个对象,同时这个对象会返回。

修改 this 默认指向

     除了指定函数中 this 的指向之外,JavaScript 还提供了一套机制来修改 this 的默认指向,可以让函数中的 this 指向想让它指向的对象。

     ES5 中通常采用函数上下文调用模式,如 call、apply、bind 等,

 <script type="text/javascript">
        /**全局变量,相当于给 window 对象添加属性*/
        var id = 120;
        var name = "华太师";

        // json 对象
        let json = {
            id: 110,
            name: "华安"
        };

        //全局函数,相当于给 window 添加方法
        function showTime() {
            console.log(this);
            console.log(this.id, this.name);
        }

        //默认情况下调用时,其中的this表示window对象
        showTime();
        //使用 call 将 json 对象替换默认原来的 window 对象
        showTime.call(json);
    </script>

运行结果如下:

     ES6 开始可以使用箭头函数 ()=> ,它会将 this 表示的对象往外抛一级,如下所示:

    <!-- 箭头函数属于 ES6 ,所以 type 类型要改成 module-->
    <script type="module">
        /**
         * Tiger 相当于一个类
         * @constructor
         */
        let Tiger = function () {
            this.id = 110;
            this.name = "宁王";
            /**Dog 是一个 Json对象*/
            this.Dog = {
                id: 120,
                name: "华太师",
                /**非箭头函数写法*/
                showInfo1: function () {
                    console.log(this.id, this.name);
                },
                /**箭头函数写法*/
                showInfo2: ()=> {
                    console.log(this.id, this.name);
                }
            }
        };
        /**这种写法已经说过了,调用 showInfo1 函数的是 Dog 对象,里面的 this 就表示 Dog 对象*/
        new Tiger().Dog.showInfo1();
        /**虽然调用 showInfo2 函数的是 Dog 对象,但是箭头函数会往外抛一层,里面的 this 表示的是 Tiger*/
        new Tiger().Dog.showInfo2();
    </script>

     运行结果如下:

猜你喜欢

转载自blog.csdn.net/wangmx1993328/article/details/84333664