zoukankan      html  css  js  c++  java
  • JS 中的 this 指向问题

    JavaScript 中的 this:
    this指向是在运行函数时确定的,而不是定义函数时候确定的
    匿名函数的执行环境具有全局性,因此其this 对象通常指向window(在通过call()或apply()改变函数执行环境的情况下,this 就会指向其他对象)

    全局上下文:无论是否在严格模式下,在全局执行上下文中(在任何函数体外)this都指代全局对象

        如:
            1、console.log(this === window); // true
            2、var girl={name:"amy",testThis:this}; console.log(girl.testThis); // window
              (可理解为:var girl=new Object(); girl.name="amy"; girl.testThis=this;(指向window)


    函数上下文:在函数内部,this的取值取决于函数被调用的方式

        1、简单调用:
        function f1(){
          return this;
        }
        f1() === window; //在浏览器中,全局对象是window
        非严格模式下,且this的值不是由该调用设置时(具体说就是不由该调用通过 call、apply、bind 这些方法来设置),this的值默认指向全局对象 严格模式下,this将保持它进入执行上下文时的值 所以默认为undefined
        
        2、如果要想把 this 的值从一个上下文传到另一个,就要用 call 或者apply 方法
        
        3、bind方法:
        ECMAScript 5 引入了 Function.prototype.bind。调用f.bind(someObject)会创建一个与f具有相同函数体和作用域的函数,但是在这个新函数中,this将永久地被绑定到了bind的第一个参数,无论这个函数是如何被调用的
        
        4、箭头函数:this与封闭词法上下文的this保持一致(即this被设置为它创建时的上下文)。如果将this的值传给call、bind、apply,它将被忽略,不过仍然可以为为调用添加参数,不过第一个参数应设置为null
        
        5、作为对象的方法:当作为对象的方法被调用时,它们的this是调用该函数的对象,并且此时this的绑定只受最靠近的成员引用的影响
        
        6、原型链中的this:this指向的是调用该方法的对象,就像该方法在对象上一样

        7、getter(与setter)中的this:用作getter(或setter)的函数会把this绑定到获取(或设置)属性的对象上

        8、作为构造函数:this被绑定到正在构造的新对象(虽然构造器返回的默认值是this所指的那个对象,但它仍可以手动返回其他的对象)
        
        9、作为一个DOM事件处理函数:this指向触发事件的元素
        
        10、作为一个内联事件处理函数:this指向监听器所在的DOM元素
            如:
                1、<button onclick="alert(this.tagName.toLowerCase());"> Show this </button> this指向button(注意只有外层代码中的this是这样设置的)
                
                2、<button onclick="alert((function(){return this})());">  Show inner this </button> 这种情况下,没有设置内部函数的this,相当于函数简单调用的情况,所以它指向global/window对象

    部分代码示例:

      1 <!DOCTYPE html>
      2 <html lang="en">
      3 <head>
      4     <meta charset="UTF-8">
      5     <title>This</title>
      6 </head>
      7 <body>
      8 
      9 <script>
     10     //全局上下文:无论是否在严格模式下,在全局执行上下文中(在任何函数体外)this都指代全局对象 
     11     var girl={
     12         name:"amy",
     13         testThis:this
     14     };
     15     /*
     16         可理解为:
     17         var girl=new Ojbect();
     18         girl.name="amy";
     19         girl.testThis=this;
     20     */
     21     console.log(girl.testThis);//window
     22 </script>
     23 
     24 <script>
     25     console.log("JS 是基于词法作用域的语言,函数在定义它的作用域中执行,而不是在调用它的作用域中执行");
     26     console.log("类的方法默认是不会绑定 this 的,作为对象的方法:当作为对象的方法被调用时,它们的this是调用该函数的对象,并且this的绑定只受最靠近的成员引用的影响");
     27     console.log("-----------About Amy --------------");
     28     var Amy={
     29             name:"Amy",
     30             sex:"girl",
     31             amyOutter:function(){
     32                 console.log("amyOutter:",this);
     33                 return function(){
     34                     console.log("amyAnonymous:",this);
     35                 };
     36             }
     37         };
     38     console.log("----Amy.func amyOutter -----");
     39     var amy_anony=Amy.amyOutter();
     40     //输出: amyOutter: {name: "Amy", sex: "girl", amyOutter: ƒ}
     41     // 解析:作为对象的方法调用
     42 
     43     console.log("----Amy.func amyOutter quote-----");
     44     var quote=Amy.amyOutter;//获取Amy.amyOutter函数的引用
     45     quote();
     46     //输出:amyOutter: Window {postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, frames: Window, …}
     47     // 解析:这里相当于简单调用
     48     
     49     console.log("----Amy.func amyAnonymous-----");
     50     amy_anony();
     51     //输出: amyAnonymous: Window {postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, frames: Window, …}
     52     // 解析:直接调用返回的匿名函数
     53 
     54     amy_anony.call(Amy);
     55     //输出: amyAnonymous: {name: "Amy", sex: "girl", amyOutter: ƒ}
     56     // 解析:Amy用call调用返回的匿名函数
     57     
     58 </script>
     59 
     60 <script>
     61     console.log("-----------About Mike -----------");
     62     var Mike={
     63         name:"Mike",
     64         sex:"boy",
     65         mikeOutter:function(){
     66             console.log("mikeOutter:",this);
     67             (function(){
     68                 console.log("mikeAnonymous:",this);
     69             })();
     70         }
     71     };
     72 
     73     console.log("----Mike.func mikeOutter---");
     74     Mike.mikeOutter();
     75     //输出: mikeOutter: {name: "Mike", sex: "boy", mikeOutter: ƒ}
     76     // 解析:作为对象的方法调用  
     77     //输出: mikeAnonymous: Window {postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, frames: Window, …}
     78     // 输出:window 解析:匿名函数被调用
     79 
     80     console.log("----Mike.func mikeOutter quote-----");
     81     var quote=Mike.mikeOutter;//获取Mike.mikeOutter函数的引用
     82     quote();
     83     //输出:mikeOutter: Window {postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, frames: Window, …}
     84     // 解析:这里相当于简单调用
     85     //输出: mikeAnonymous: Window {postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, frames: Window, …}
     86     // 解析:匿名函数被调用
     87 
     88     console.log("---Mike func call---");
     89     Mike.mikeOutter.call(Amy);
     90     //输出: mikeOutter: {name: "Amy", sex: "girl", amyOutter: ƒ}
     91     // 解析:Amy 用call调用返回的匿名函数 
     92     //输出:mikeAnonymous: Window {postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, frames: Window, …}
     93     // 解析:匿名函数被调用
     94 
     95 </script>
     96 
     97 <script>
     98     console.log("-----------About Guang -----------");
     99     var Guang={
    100         name:"Guang",
    101         sex:"boy",
    102         GuangOutterOne:function(){
    103             console.log("GuangOutterOne:",this);
    104             var that=this;
    105             // 正确 that 中保留了对 this 的引用
    106             this.GuangOutterTwo(function(){
    107                 that.GuangOutterThree();                
    108             });
    109             
    110             // 正确 匿名函数直接绑定 this
    111             // this.GuangOutterTwo(function(){
    112             //     this.GuangOutterThree();                
    113             // }.bind(this));
    114 
    115             // 出错 匿名函数作参数 this 为 window ,window 无 GuangOutterThree 方法
    116             // this.GuangOutterTwo(function(){
    117             //     this.GuangOutterThree();                
    118             // });
    119         },
    120         GuangOutterTwo:function(cb){
    121             console.log("GuangOutterTwo:",this);
    122             cb();
    123         },
    124         GuangOutterThree:function(){
    125             console.log("GuangOutterThree:",this);
    126         }
    127     };
    128 
    129     console.log("----Guang.func GuangOutterOne---");
    130     Guang.GuangOutterOne();
    131     //输出:GuangOutterOne: {name: "Guang", sex: "boy", GuangOutterOne: ƒ, GuangOutterTwo: ƒ, GuangOutterThree: ƒ} 
    132     //解析:作为对象的方法调用  
    133 
    134     //输出: GuangOutterTwo: {name: "Guang", sex: "boy", GuangOutterOne: ƒ, GuangOutterTwo: ƒ, GuangOutterThree: ƒ}
    135     //解析: GuangOutterOne 中的 this 指向 Guang 调用 Guang 中的 GuangOutterTwo 方法
    136 
    137     //输出: GuangOutterThree: {name: "Guang", sex: "boy", GuangOutterOne: ƒ, GuangOutterTwo: ƒ, GuangOutterThree: ƒ}
    138     //解析: that 保留对 this 的引用 调用 Guang 中的 GuangOutterTwo 方法
    139    
    140 
    141 </script>
    142 
    143 <script>
    144     console.log("JS 是基于词法作用域的语言,函数在定义它的作用域中执行,而不是在调用它的作用域中执行");
    145     console.log("箭头函数:this与封闭词法上下文的this保持一致(即this 被设置为他被创建时的上下文)");
    146     var foo=(()=>this);
    147     /*
    148         可以把箭头函数看成是
    149         var foo=function(){
    150             //other code
    151             return this;
    152             //此处this所在的函数被创建时是在全局环境中 因为 this被设置为他被创建时的上下文 所以 this就被设置为window
    153         };
    154     */
    155     // 由下可见 无论如何,foo 中的 this 都被设置为他被创建时的上下文(在上面的例子中,就是全局对象)
    156     // 注意:对于箭头函数 如果将this传递给call、bind、或者apply,它将被忽略 不过你仍然可以为调用添加参数,不过第一个参数(thisArg)应该设置为null
    157     var obj = {foo: foo};
    158     console.log("直接调用:",foo()===window,", call调用:",obj.foo() === window,", apply调用:",foo.call(obj) === window,", bind绑定:",foo.bind(obj)() === window); // true true true true
    159     
    160    //这同样适用于在其他函数内创建的箭头函数:这些箭头函数的this被设置为封闭的词法上下文的
    161     console.log("-----------About John ------------------");
    162     var John={
    163         name:"John",
    164         johnOutter:function(){
    165             //console.log("johnOutter",this);//johnOutter中的this具体情况可参考上面的Amy和Mike实例
    166             var x=(()=>this);
    167             //此处this所在的函数被创建时是在johnOutter中  因为 this被设置为他被创建时的上下文 所以 this就被设置为 johnOutter 函数中的this
    168             return x;
    169         }
    170     }
    171 
    172     var fn=John.johnOutter();//获取返回的函数 若去掉johnOutter中console.log语句的注释 输出:John 解析:解析:作为对象的方法调用 
    173     console.log("John.johnOutter():",fn());
    174     //输出:John.johnOutter(): Object { name: "John", johnOutter: johnOutter() }
    175     //解析:此时johnOutter函数由John调用 所以johnOutter函数中的this为John,而箭头函数的this被设置为johnOutter的this
    176 
    177     var quote=John.johnOutter;//获取John.johnOutter函数的引用
    178     console.log("quote:",quote()());
    179     //输出:window 
    180     //解析:此时quote获取johnOutter的引用,quote()相当于简单调用,所以johnOutter函数中的this为window,而箭头函数的this被设置为johnOutter的this
    181     
    182     /**
    183      * 对于箭头函数:
    184      * 1、确定箭头函数是在哪个执行环境中被创建的
    185      * 2、根据执行环境确定this被设置为哪个执行环境
    186      * 3、最后对函数的调用参考对象中的方法调用即可
    187      * 总结可以简单理解为:
    188      * 箭头函数的this在全局执行上下文创建时 它的this就是全局上下文中的this 
    189      * 箭头函数的this在非全局执行上下文创建时,它的this就与封闭词法上下文中的this保持一致
    190 */ 191 192 </script> 193 194 </body> 195 </html>
  • 相关阅读:
    虚拟机的类加载机制
    数组
    Intellij快捷键
    Wireshark过滤器语法设置
    Git命令(转)
    Git命令
    字节码指令简介(转)
    Java异常了解
    Class类文件的结构
    垃圾收集器与内存分配策略(六)之内存分配与回收策略
  • 原文地址:https://www.cnblogs.com/go4it/p/9678121.html
Copyright © 2011-2022 走看看