this

作者: 苦瓜_6 | 来源:发表于2018-08-15 22:01 被阅读0次

    当一个函数被调用时,会创建一个活动记录(执行上下文)。这个记录会包括函数在哪里被调用(调用栈)、函数的调用方式、传入的参数等信息。 this 就是这个记录的一个属性,会在函数执行的过程中用到。

    随着函数使用场合的不同,this的值会发生变化。但是有一个总的原则,那就是this指的是,调用函数的那个对象。

    一、作为函数调用

    函数直接调用时的this
    console.log(this);  //  window
    
    function fn(){
        console.log(this);
    }
    
    fn(); // 在函数被直接调用时this绑定到全局对象。在浏览器中,window 就是该全局对象
    
    
    内部函数的this

    函数嵌套产生的内部函数的this不是其父函数,仍然是全局变量

    function fn(){
        function fn1(){
            console.log(this);
        }
        fn1();
    }
    
    fn(); //  window  
    

    改写一下:

    function fn(){
        console.log('这是fn')
        console.log(this);   //  window
        function fn1(){
            console.log('这是fn1')
            console.log(this);  //   window
          function   fn2() {
               console.log('这是fn2')
               console.log(this);  // 依旧是window
             }
           fn2 ()
        }
        fn1();
    }
    
    fn();  
    
    setTimeout、setInterval 中的this
    function fn(){
        console.log(this);   //  window
        setTimeout(function(){
            console.log(this);  // window
        }, 200);
    }
    
    fn()
    

    二、 作为构造函数调用

    作为构造函数调用时,this指向实例对象

    function Cat(name){
        this.name = name;
    }
    Cat.prototype.sayName = function(){
        console.log(this.name);
    };
    
    var p1 = new Cat('Munchkin');
    p1.sayName();  // Munchkin
    

    三、作为对象方法调用

    • 隐式绑定, 直接调用 cat.fn()
    var cat = {
        name: 'Munchkin',
        fn : function(){
            console.log(this);
        }
    };
    cat.fn(); // 指向调用函数的对象 cat 
    

    对象属性引用链中只有上一层或者说最后一层在调用位置中起作用。

    • 常见陷阱 ( “隐式丢失”): 将cat.fn 赋值给其他对象再调用
    var fn2 = cat.fn;
    
    fn2(); //  window
    
    • 将对象方法作为参数传递给函数,然后调用函数
    function foo(){
      console.log(this.a)
    }
    function doFoo(fn) {
      console.log(fn)
      fn(); // <-- 调用位置!
    }
    var obj = {
      a: 2,
      foo: foo
    }
    var a  = "oops, global";
    doFoo(obj.foo); //  "oops, global"
    

    参数传递其实就是一种隐式赋值,因此我们传入函数时也会被隐式赋值(与上个例子类似)。

    四、 DOM对象绑定事件

    在事件处理程序中this代表事件源DOM对象(低版本IE有bug,指向了window)

    <body>
      <button>click</button>
      
      <script>
        let btn = document.querySelector('button');
        btn.addEventListener('click', function(e){
          console.log(this);  //   <button>click</button>
          var _document = this;
          setTimeout(function(){
              console.log(this);  //  window
              console.log(_document);  //  <button>click</button>
          }, 200);
      }, false);
      </script>
    </body>
    

    五、使用 call ,apply ,bind 改变this 指向(显式绑定)

    Function.prototype.call

    fn.call(context, param1, param2...)

    Function.prototype.apply

    fn.apply(context, paramArray)

    Function.prototype.bind

    bind,返回一个新函数,并且使函数内部的this为传入的第一个参数

    var fn3 = obj1.fn.bind(obj1);
    fn3();
    
    三者比较

    共同点

    • 都可以改变 this 指向,第一个参数都是希望设置的this对象

    不同点

    • call 和 apply的不同之处在于call方法接收参数列表,而apply接收参数数组; - call 和 apply 都是直接调用函数,而bind 是返回一个改变了this 指向的新函数,供后面调用(不是直接调用)

    七、 关于 this 的题目

    var name = 'window'
    
    var person1 = {
      name: 'person1',
      show1: function() {
        console.log(this.name)
      },
      show2: () => console.log(this.name),
      show3: function() {
        return function() {
          console.log(this.name)
        }
      },
      show4: function() {
        return () => console.log(this.name)
      }
    }
    var person2 = {
      name: 'person2'
    }
    
    

    以下各输出什么:

    person1.show1() 
    person1.show1.call(person2)
    
     person1.show2() 
     person1.show2.call(person2)
    
     person1.show3()()
     person1.show3().call(person2)
     person1.show3.call(person2)()
    
    person1.show4()()
    person1.show4().call(person2)
    person1.show4.call(person2)()
    

    参考:

    • 《你不知道的JS》 P82~ P101

    相关文章

      网友评论

          本文标题:this

          本文链接:https://www.haomeiwen.com/subject/rkzgpftx.html