js中的this指向问题

1.产生的问题

  • 1.类中的this指向
  • 2.方法中的this指向
  • 3.匿名函数中的this指向
  • 4.怎么解决this指向问题

2.样例及解决

1.类中的this指向

<script type="text/javascript">
        class Person{
            // 构造器
            constructor(id, name){
                console.log("类中构造器的this指向: ", this)
                this.id = id
                this.name = name
            }
            // 普通方法
            eat(){
                console.log("类中方法的this指向: ", this)
            }
        }
        const p1 = new Person(1, 'lily')
        p1.eat(); // 通过Person实例调用eat方法,其中this是Person的实例
        console.log("===================")
        const temp = p1.eat // 将Person类的特殊属性(方法)eat赋值给temp
        console.log("方法的定义: ", temp)   // 输出方法的定义
        console.log("将Person类内部的eat方法赋值给temp变量,并调用:")
        temp()  // 直接调用temp方法,this是undefined
    </script>

完整输出为如下:

image.png

  • 1.最后一行temp() // 直接调用temp方法,this是undefined输出为什么是undefined,而不是Person实例或者window对象?
    • 原因:因为js在类中自动开启了严格模式("use strict";//禁止this关键字指向全局对象),所以这里的this为undefined。

2.方法中的this指向

<script type="text/javascript">
        function test1(){
            console.log(this)   // 方法中直接输出this指向window对象
        }
        function test2(){
            "use strict";
            console.log(this)   // 加了严格模式,输出this指向为undefined
        }
</script>

输出如下:

image.png

3.匿名函数中的this指向

<script type="text/javascript">
        // 匿名函数测试1
        const temp1 = {
            id: 123,
            temp1: function(){
                console.log("外部this指向: ", this) // 输出Object对象(及js对象)
                return function(){
                    console.log("内部this指向: ", this) // 输出window对象
                }
            }
        }
        console.log("匿名函数定义: ", temp1.temp1())  // 输出外部this并同时输出匿名函数定义
        temp1.temp1()() // 内部的匿名函数调用
        console.log("================")
        // 匿名函数测试2
        const btn = document.getElementById('btn').addEventListener('click', ()=>{
            console.log("监听事件的匿名函数中this指向: ", this)
            btnInner();
            btnInner1();

            (function(){
                console.log("匿名函数中的匿名函数中的this指向: ", this)
            })()
        })
        function btnInner(){
            console.log("匿名函数调用非严格模式中的this指向: ", this)
        }
        function btnInner1(){
            "use strict";
            console.log("匿名函数调用严格模式中的this指向: ", this)
        }
</script>

输出如下:

image.png

4.怎么解决this指向问题

  • 1.全局定义一个变量that,将this赋值给变量that,然后使用(视开发情况而使用)
  • 2.使用call,apply,bind方法解决this指向
  • 1.先说call
    call(this指向, 函数参数, 函数参数...), this指向就是需要把哪个对象实例传进去,函数参数就是调用call方法的那个函数的参数(有点绕口,看例子)。这个例子中myIntroduce有俩个参数,name没有使用this访问,所以可以直接传入参数输出出来,而age使用this去访问的(本来this应该指向objCall,但是此时this却为undefined,这并不是我们所期望的),所以使用call改变this的指向由undefined到objCall就可以访问到age。注意:我这里专门传入第二个参数19,结果却输出13,原因很简单(没有this.age=age),这里的age并没有set到objCall的原型链上。

<script type="text/javascript">
        const objCall = {
            age: 13,
            myIntroduce: function(name, age){
                console.log("我是:", name, ",性别:", this.age)
            }
        }
        const callIntroduce = objCall.myIntroduce
        callIntroduce('约翰', 19)   // this指向window对象, 但是我们期望的是this指向objCall对象
        // 使用call
        callIntroduce.call(objCall, '约翰', 19)
</script>
  • 2.再说apply
    apply(this指向, [函数参数, 函数参数...]),没错,apply和call的区别就是apply的第二个参数是一个数组。(例子如下),从下面这个例子可以看出方法1.apply(this指向另一个对象noObjApply ,[参数1, 参数2]),而在noObjApply中由一个与方法1同名的方法2,最后的结果是方法1可以使用noObjApply中的属性,而不会直接换到方法2去

<script type="text/javascript">
        const objCall = {
            age: 13,
            myIntroduce: function(name, age){
                console.log("我是:", name, ",性别:", this.age)
            }
        }
        const noObjApply = {
            age: 20,
            myIntroduce: function(name, age){
                console.log("我是noObj名字为:", name, ",性别:", this.age)
            }
        }
        const callIntroduce = objCall.myIntroduce
        callIntroduce('约翰', 19)   // this指向window对象, 但是我们期望的是this指向objCall对象
        // 使用apply
        callIntroduce.apply(objCall, ['约翰', 19])
        callIntroduce.apply(noObjApply, ['约翰', 19])
</script>

输出如下:

image.png

  • 3.最后说bind
    bind(this指向, 参数1, 参数2...),这个例子和前俩个差不多,有一点就是bind方式改变this指向返回一个新的函数,需要自己去调用这个函数。

<script type="text/javascript">
       const objCall = {
            age: 13,
            myIntroduce: function(name, sex, age){
                console.log("我是:", name, ",性别:", sex, ",年龄:", this.age)
            }
        }
        const noObjApply = {
            age: 20,
            myIntroduce: function(name, sex, age){
                console.log("我是noObj名字为:", name, ",性别:", sex, ",年龄:", this.age)
            }
        }
        const callIntroduce = objCall.myIntroduce
        callIntroduce('约翰', '男', 19)   // this指向window对象, 但是我们期望的是this指向objCall对象
        const changeThisP = callIntroduce.bind(objCall, '约翰', '男', 19)   // bind返回一个函数,不会立即执行
        changeThisP()
        const changeThisP1 = callIntroduce.bind(noObjApply, '约翰', '男', 19)   // bind返回一个函数,不会立即执行
        changeThisP1()
        const changeThisP2 = callIntroduce.bind(objCall, ['约翰', '男', 19])   // bind返回一个函数,不会立即执行
        changeThisP2()
        const changeThisP3 = callIntroduce.bind(noObjApply, ['约翰', '男', 19])   // bind返回一个函数,不会立即执行
        changeThisP3()
</script>

输出如下:


image.png

3.问题总结

  • 1.call和apply修改this指向都是调用的时候执行,唯一的不同点是传参问题,call的第二个参数以后直接传递参数,apply的第二个参数却是一个数组,调用方式都是及用及调。
  • 2.bind与call和apply的不同
    • 1.参数问题,bind的第二个参数如果为数组,需要改变this指向的方法内部使用参数的时候需要下标访问,如果第二个参数不是数组,而是多个参数,参数传递方式和call的一样。
    • 2.调用问题,call和apply都是直接调用的,而bind则是返回一个函数,需要的时候再去调用。
  • 3.附加: 还有一个箭头函数()=>{},箭头函数中没有自己的this,如果在箭头函数中使用了this这个关键字(使用不报错),箭头函数就会找其外侧函数的this作为箭头函数的this去使用。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,684评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,143评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,214评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,788评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,796评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,665评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,027评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,679评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,346评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,664评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,766评论 1 331
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,412评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,015评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,974评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,073评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,501评论 2 343

推荐阅读更多精彩内容