js中this的指向问题

一.引言

   首先我们需要知道:javascript中的this不是指定到一个固定的对象的,它会根据我们函数的调用方式不同,指向不同的对象。
   学习this的目的:在面向对象的编程中使用较多,熟悉在不同场景中this的指向,能够帮助我们更好理解代码,代码也会更清晰。

二.this指向的分类

1.this指向window
  (1) js文件中的this指向window
  (2) 通过函数名+()形式调用函数this指向window
  (3) 定时器、延时器回调函数里this指向window
  (4) 行内绑定事件(DOM0级)通过函数名+()形式调用this指向window
2.this指向事件调用的节点对象
 (1)行内绑定事件时通过函数名+(this)形式,this指向调用的节点对象
 (2)DOM1级事件调用,this指向调用的节点对象
 (3)DOM2级事件调用,this指向调用的节点对象
3.this指向传入的第一个参数
  (1)bind()
  (2)call()
  (3)apply()
4.this指向对象
  (1)通过对象.方法名+()形式调用this指向对象
5.this指向数组
  (1)通过数组[下标]+()形式调用,this指向数组
6.this在箭头函数中的指向
  (1)箭头函数中this指向它的宿主对象

三.代码讲解

1.this指向window,如果在严格模式下this无法指向全局window
  (1) js文件中的this指向window

 <script>
        // js中直接打印this
        console.log(this);//Window {window: Window, self: Window, document: document, name: '', location: Location, …}
    </script>

 (2) 通过函数名+()形式调用函数this指向window

 <script>
        function fn(){
            console.log(this);//Window {window: Window, self: Window, document: document, name: '', location: Location, …}
        }
        // 通过函数名()形式调用this指向window
        fn()
    </script>

 (3) 定时器、延时器的回调函数里this指向window

 <script>
        // 定时器
        // setInterval(function(){
        //     console.log(this);  //this指向window,每隔1秒在控制台输出一次
        // },1000)

        // 延时器
        setTimeout(function(){
            console.log(this); //延迟1s输出一次this指向window
        },1000)
        
    </script>

 (4)行内绑定事件(DOM0级)通过函数名+()形式调用this指向window

<body>
    <div onclick="clickFn()">这是内容</div>
    <script>
        function clickFn(){
            console.log(this); //点击div时打印出的this指向window
        }
    </script>
</body>

2.this指向事件调用的节点对象
 (1)行内绑定事件时通过函数名+(this)形式,this指向调用的节点对象

 <div onclick="clickFn(this)">这是内容</div>
    <script>
        // str是接收函数传递过来的this,指向的是调用这个事件的节点对象
        function clickFn(str){
            console.log(str);  //str指的是:调用这个<div onclick="clickFn(this)">这是内容</div>
        }
    </script>

 (2)DOM1级事件调用,this指向调用的节点对象,通过节点对象.onclick调用函数称之为DOM1级事件。

 <button id='btn'>按钮</button>
    <script>
        // 获取元素
        let btn=document.querySelector('#btn')

        // DOM1级事件
        btn.onclick=function(){
            console.log(this);  //结果为:button这个节点对象 <button id="btn">按钮</button>
        }

    </script>

 (3)DOM2级事件调用,this指向调用的节点对象.DOM2级事件是使用节点对象.addEventListener()调用函数。
函数补充:addEventListener('事件名不加on',callback,true/false):true表示冒泡,false表示捕获

 <button id='btn'>按钮</button>
    <script>
           // 获取元素
           let btn=document.querySelector('#btn')
           btn.addEventListener('click',function(){
               console.log(this);  //结果指向 button这个节点对象,<button id="btn">按钮</button>
           })
    </script>

3.this指向传入的第一个参数
 (1)bind(this的指向,参数2,参数3):返回一个新函数并改变这个新函数中的this指向bind的第一个参数,后面的参数是调用时给函数传递的参数.

<body>
  <ul>
    <li>哈哈</li>
    <li>呵呵</li>
    <li>嘿嘿</li>
    <li>嘻嘻</li>
    <li>哼哼</li>
  </ul>
  <script>
    // 获取元素节点
    let lisObj = document.querySelectorAll('li');
    // 使用ES6新增的方法获取元素节点得到的数组可以直接使用数组的方法forEach
    lisObj.forEach(function (li) {
      // 给每一个Li绑定事件
      li.onclick = function () {
        // console.log(this);  //这个this指向的是调用事件的节点对象
        setTimeout(function () {
            //原本延时器里面this指向window
          // 加个bind改变setTimeout这个函数里面的this指向是bind的第一个参数
          console.log(this)
        }.bind(this), 1000);
      }
    });
  </script>
</body>

  (2)call(this指向,参数2,参数3):调用函数并且改变这个函数中的this指向。

<script>
    function Fn1(name,age){
        this.name=name
        this.age=age
        // console.log('Fn1中this的指向',this); //原本this指向Fn1实例化的对象
        console.log('Fn1中this的指向',this)  //现在Fn1中this的指向为Fn2 {score: 100, name: 'zs', age: 19}
    }
   
    function Fn2(name,age,score){
        this.score=score
        // 使用call这个函数,改变Fn1中this的指向call里面的第一个参数this
        // 第一个参数this是指的Fn2这个实例化的对象
        // 并且调用Fn1这个函数
        Fn1.call(this,name,age)
    }
    // 实例化Fn2的对象
    let f2=new Fn2('zs',19,100)
</script>

  (3)apply(this的指向,数组[]):调用函数并改变这个函数中的this指向。

<script>
      function Fn1(name,age){
          this.name=name
          this.age=age
          // console.log('Fn1中的this指向:',this);  //原来Fn1中的this指向: Fn1 {name: 'ls', age: 20}
          console.log('Fn1中的this指向:',this); //现在Fn1中的this指向: Fn2 {score: 80, name: 'zs', age: 29}
      }
      // let f1=new Fn1('ls',20)
      function Fn2(name,age,score){
          this.score=score
          // 这里的this指向的是Fn2实例化的对象
          Fn1.apply(this,[name,age])
      }
      let f2=new Fn2('zs',29,80)
  </script>

4.this指向对象
  (1)通过对象.方法名+()形式调用this指向对象

<script>
        let obj={
            name:'zs',
            age:18,
            score:90,
            say(){
                console.log(this);  //this指向的是对象:{name: 'zs', age: 18, score: 90, say: ƒ}
            }
        }
        obj.say()
    </script>

5.this指向数组
  (1)通过数组[下标]+()形式调用,this指向数组

 <script>
        function fn(){
            console.log(this); //this指向数组:['a', 'b', 'c', ƒ]
        }
        // 数组元素是函数名
        let arr=['a','b','c',fn]

        // 通过数组名下标+()调用函数,this指向数组
        arr[arr.length-1]() 
    </script>

6.this在箭头函数中的指向
  (1)箭头函数中this指向它的宿主对象

  <div>这是内容</div>
   <script>
    //    获取元素(
    let div=document.querySelector('div')
    // 给div元素绑定事件
    div.onclick=function(){
        // console.log(this);  //this指向调用事件的节点对象:<div>这是内容</div>
        setInterval(() => {
            console.log(this); //原本里面的this指向的是window,使用箭头函数,就指向它的宿主对象(也就是它的上一级):<div>这是内容</div>
        }, 2000);
    }
   </script>

四.总结

 总之,this在不同的调用方式下指向不同的对象,小伙伴们可以熟记一些常见的this指向。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,826评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,968评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,234评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,562评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,611评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,482评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,271评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,166评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,608评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,814评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,926评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,644评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,249评论 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,866评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,991评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,063评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,871评论 2 354

推荐阅读更多精彩内容