JavaScript 高级编程,this指向问题【2】

目录

part1:

法则:

例题1:

例题2:

例题3:

例题4:

例题5:

例题6:

part2:

 例题1:

例题2:

例题3:

例题4:

part3:

例题1:定时器指向

例题2:定时器this特殊情况【据说面试可能会有】

例题3:bind call apply的this指向

问题4:this与箭头函数

问题5: this总是指向事件的触发者还是事件的绑定者?触发者和绑定者不一样时?


法则:

1. this指向的永远是一个对象

2. 指向的是哪个对象,取决于谁调用了它

例题1:

问obj.f()打印的是什么?

        function fun() {
            console.log(this.s); 
        }
        var obj = {
            s: 1,
            f: fun
        }
        var s = 2;
        obj.f();

打印的是1;

原因是:

1. obj.f表示调用obj对象里面的f方法,

2. f指向fun这个函数,上面的式子可以改成下面的式子

        function fun() {
            console.log(this.s); 
        }
        var obj = {
            s: 1,
            f:  function () {
            console.log(this.s);  // 看这里
        }
        }
        var s = 2;
        obj.f();

因此直接理解为obj对象调用本身的方法,this指向obj这个对象。

例题2:

问直接调用fun(),输出的是什么?

        function fun() {
            console.log(this.s); 
        var obj = {
            s: 1,
            f: fun
        }
        var s = 2;
        fun();
  • s是2
  • 因为是window调用fun()函数。而不是obj调用,尽管obj里面的f指向fun函数
  • 所以this指向window这个对象
  • s=2是全局作用域的变量

      

例题3:

问A.f()和B.f()分别输出的什么?

        var A = {
            name: 'jmq',
            f: function () {
                console.log(this.name);
            }
        };

        var B = {
            name: 'syc',
            
        };

        B.f = A.f;
        A.f(); 
        B.f(); 

A.f()输出的是jmq,

B.f()输出的是syc

为什么?

关键看懂B.f = A.f()是什么意思?

意思是A里面的f方法赋值给B,是赋值的意思!!类似下图的结果

       var A = {
            name: 'jmq',
            f: function () {
                console.log(this.name);
            }
        };

        var B = {
            name: 'syc',
            f: function () {
                console.log(this.name); // 看这里
            }
            
        };

        B.f = A.f;
        A.f(); // jmq
        B.f(); // syc

而A和B各自调用本身的方法f,this指向的就是本身

例题4:

和例3相似的题目,例3理解了,这题也可以理解

        // 问最终的结果输出的是什么?
        function fo() {
            console.log(this.a);
        }
        var o1 = {
            a: 3,
        };
        var o2 = {
            a: 6,
        };
        var a = 9;
        o1.f = fo;
        console.log(o1);

        o2.f = o1.f;
        o1.f(); // 输出什么?
        o2.f(); // 输出什么?

o1.f()输出3

o2.f()输出6

为什么?对于o1和o2的操作和例3类似,本质还是赋值。可以看成下面的代码

        // 问最终的结果输出的是什么?
        function fo() {
            console.log(this.a);
        }
        var o1 = {
            a: 3,
            // f: function fo() {
            //     console.log(this.a);
            // }
        };
        var o2 = {
            a: 6,
            // f: function fo() {
            //     console.log(this.a);
            // }
        };
        var a = 9;
        o1.f = fo;
        console.log(o1);

        o2.f = o1.f;
        o1.f(); // 3
        o2.f(); // 6
        // 为什么?
        // 跟之前一题很相似,给o1增加fo方法,同时通过o2.f = o1.f;让o2也有这个方法
        // 那么就是对象调用方法,this指向对象

例题5:

问最终输出的是几?

        // 问最终的结果输出是几?
        function foo() {
            console.log(this.a);
        }
        var obj2 = {
            a: 2,
            fn: foo
        };

        var obj1 = {
            a: 1,
            o1: obj2
        };
        obj1.o1.fn(); // 输出的是啥?

结果:

输出的是2.

       · 为什么是2?根据法则:this指向的一定是一个对象,关键是指向了哪个对象?

       · obj1.o1本质上是obj2,所以,据此判断就是obj2调用了foo函数,

       · 就是指向obj2,里面a是2

this不仅仅是指向调用的对象,指向的还是调用的最近一级的对象

例题6:

        var a = 10;
        var obj = {
            a: 120,
            method: function () {
                var bar = function () {
                    console.log(this.a); // 输出什么?
                };
                bar();
                return this.a; // 输出什么?
            }
        }
        console.log(obj.method());

第一个this.a输出是10

第二个this.a输出是120

为什么?

第一个this.a:

        首先, 第18行输出10,关键看bar这个函数是谁调用的是window调用的

        其次, 为什么是window调用的?

        再者, 仔细观察,只是在obj里面的方法里面声明了一个函数,在方法里面调用了函数,可以理解为obj调用了method,但是obj并没有直接调用bar

        最后, 是window调用了bar。指向window,所以是10

第二个this.a:

      return this.a;因为是在method里面return this而是obj调用的method方法所以this指向obj,打印的是120

总结:

1. 对象调用了方法,那么this指向对象。如例1例3例4

2. 全局下执行函数,this指向window,如例2

3. 如obj1.o1.fn(),假如对象调用了自己的一个属性o1,o1的属性值指向另外一个对象obj2,obj2的fn又是一个函数,这个函数里面打印this,this指向最近的obj2

4. 如果一个对象里面的方法1,方法里面还有一个函数2,函数2在对象的方法1里面执行,函数2打印this,指向的全局window,而不是这个对象。

这篇文章只需要额外理解第四个即可,其他的都按照我的第一个文章里面列举的去理解即可。

​​​​​​javascript 高级编程 this指向问题【1】_hangshao_123的博客-优快云博客

part2:

 例题7:

        var fullName = 'language';
        var obj = {
            fullName: 'javascript',
            prop: {
                getFullName: function () {
                    return this.fullName;
                }
            }
        };
        console.log(obj.prop.getFullName()); // 这里输出什么?
        var test = obj.prop.getFullName;
        console.log(test()); // 这里输出什么

第一个地方输出undefined

第二个地方输出language

 1. 为什么第一个地方指向undefined?

        1.1 obj是一个对象 prop也是一个对象

        1.2 是obj里面的prop这个属性调用了getFullName,本质就是prop调用了getFullName

        1.3 注意,prop的值本身就是一个对象,这个对象调用了方法,方法里面的this指向prop

        1.4 而prop里面并没有getFullName,就会打印undefined

        1.5 为什么不是报错?注意,如果对象里面没有这个值,强行打印就是undefined

        var o = {
            name: 'jmq'
        }
        console.log(o.name1); // undefined

 2. 为什么第二个地方是language?

因为这里打印language是因为test是在全局下执行

例题8:

HTML:

<input type="button" value="点击按钮1" onclick="fun()">

JavaScript:

    <script>
        function fun() {
            console.log(this);
        }
    </script>

这里特别记住,打印出来是window,写在html标签里面的onclick事件,虽然是点击事件,但是这里的fun()函数要理解为是window内置的,

类比:
alert()也是window内置的方法

 <input type="button" value="点击按钮2" onclick="alert()">

例题9:

HTML:

<input type="button" value="按钮3" id="btn3">

JavaScript:

        var btn3 = document.querySelector("#btn3");
        btn3.onclick = fun1;
        function fun1() {
            console.log(this);// 打印什么
        }

打印出来是按钮对象。为什么是按钮,不是window?

        可以理解为btn3是一个DOM对象,onclick是对象里面的一个方法,执行的函数体就是fun1里面的内容,==>最终是按钮这个对象调用了方法,所以this指向按钮

例题10:

HTML:

    <button id="btn">点击按钮</button>

JavaScript:

问,点击按钮,最终输出什么?undefined?data里面的索引为1的数据?还是……

         var userInfo = {
            data: [
                { "username": "jmq", "id": 19 },
                { "username": "syc", "id": 20 }
            ],
            getuserInfo: function () {
                var index = 1;
                console.log(this.data[index].username + ":" + this.data[index].id);
            }
        }
        var btn = document.querySelector("#btn");
        // 问,点击按钮,最终输出什么?undefined?data里面的索引为1的数据?还是……
        btn.onclick = userInfo.getuserInfo;

最终是报错,为什么报错?

 原因是:

        1.按钮点击,即便为userInfo这个对象调用本身的方法,this指向的依旧是按钮这个对象,所以按钮不存在data这个属性。按钮不存在这个属性,强行打印,就会报错

        

       2.  上面的代码可以改成如下

  btn.onclick = function () {

            var index = 1;

            console.log(this.data[index].username + ":" + this.data[index].id);

        }

如果代码改成这样调用,

         var userInfo = {
            data: [
                { "username": "jmq", "id": 19 },
                { "username": "syc", "id": 20 }
            ],
            getuserInfo: function () {
                var index = 1;
                console.log(this.data[index].username + ":" + this.data[index].id);
            }
        } 
        userInfo.getuserInfo();  // 打印的是  syc:20 不会调用

代码修改前,如何实现,按钮点击,能够不报错成功打印,可以利用bind

备注:

bind和call的相同点和不同点:

相同点:1. 都可以调用函数 2. 都可以改变this的指向 3. 返回的是一个新的函数

不同点:bind是想指定啥时候调用就啥时候调用,call是立即马上执行函数

var userInfo = {
            data: [
                { "username": "jmq", "id": 19 },
                { "username": "syc", "id": 20 }
            ],
            getuserInfo: function () {
                var index = 1;
                console.log(this.data[index].username + ":" + this.data[index].id);
            }
        } 
btn.onclick = userInfo.getuserInfo.bind(userInfo); // 这里修改了,能够点击打印数据,不会报错

例题11:定时器指向

        function fn() {
            console.log(this);
        }
        setInterval(fn, 1000); // 这里打印啥?

不管是setInterval还是setTimeout这里打印的都是window,

怎么理解?上面的定时器可以写成window.setInterval(fn, 1000); 可以把定时器理解为window的一个函数,就是window调用了定时器,进而里面的函数fn也是window调用的

例题12:定时器this特殊情况【据说面试可能会有】

        var k = {
            a: 1,
            sing: function () {
                console.log(this);
            }
        }
        setTimeout("k.sing()", 1000); // 这里打印的是啥?

        打印的是object对象。为什么?

        首先来思考,一般定时器的第一个参数是函数,但是其实也可以放一个执行体,比如

setTimeout("console.log('aa')", 1000);

        进一步来思考,最上面的k.sing() 调用,因为是k对象调用了sing方法,即便是定时器setTimeout作为window的全局对象,此时this也是指向obj对象,这里可以这样理解,也可以记住

例题13:bind call apply的this指向

        var btn = document.querySelector("#btn");
        function smell() {
            var a = 10;
            console.log(this.a);
        }
        var o = {
            a: 100,
            smell: function () {
                console.log(this.a);
            }
        }
        smell.call(o); // 打印什么
        btn.onclick = smell.bind(o); // 打印什么
        smell.apply(o); // 打印什么

第一个,立即打印100,

第二个,点击后打印100,

第三个,立即打印100

上面三个,都是通过方法,改变this的指向,this都指向o,所以打印的是o里面的a变量,都是100,只是执行函数的时间点的差别。

注意,bind是可以指定啥时候触发函数。apply和call都是立即执行这个函数。apply第二个参数是必须传递数组,call和bind第二个参数不是数组。【这里我有点忘啦,有待补充】

问题14:this与箭头函数

this总是指向函数的调用者?不一定, 箭头函数的this指向window

        var value = 8;
        var obj = {
            value: 10,
            fn: () => {
                console.log(this.value); // 打印的是8
            }
        }
        obj.fn();

发现fn这个方法是obj对象调用的,但是this指向window不指向obj;同理,this也不总是指向触发这个事件的对象

箭头函数中this 指向父级的上下文中的this,是定义的时候就确定的。

且,不可以被call apply bind改变

        const zhangsan2 = {
            name: '张三',
            sayHi() {
                console.log(this);
            },
            waitAgain() {
                setTimeout(() => {
                    // this指向 当前对象
                    console.log(this);
                })
            }
        }
        zhangsan2.waitAgain()
        // 箭头函数 this指向 当前函数所在父级的上下文对象 
        // 当前函数的父级是waitAgain函数 上下文是在zhangsan2这个对象

上面的箭头函数是一个waitAgain函数,waitAgain函数的上下文对象是zhangsan2,因此指向zhangsan2

问题15: this总是指向事件的触发者还是事件的绑定者?触发者和绑定者不一样时?

事件委托【事件委派】时,

        var ul = document.querySelector("ul");
        var lis = ul.querySelectorAll("li");
        ul.addEventListener("click", function () {
            console.log(1);
            console.log(this); // 当点击小li,打印时,this指向ul,指向事件的绑定者,而不是触发者
        })

结尾:

学习id: 201903090124-29

现在是大三学生,学习到了前后端交互阶段,如有不对的地方,欢迎指正,一起努力呀。如有转载请注明出处。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值