淺談-this

淺談-this

this簡單而又神祕,使用場景多變而又複雜,這造就了它成爲了初級javascript開發人員不肯接觸的東西,高級javascript都想探究的東西。文本亦是對this的致敬。javascript

  1. this是什麼?
    this是當前執行環境的上下文,一般由函數的調用方式決定其值。
  2. this的原理java

    首先,從函數的調用開始node

    函數的調用通常有三種狀況(ES5中)數組

    1.foo(p1,p2);
    2.obj.foo(p1,p2);
    3.foo().call(context,p1,p2);//或者apply

    一般狀況下,大部分童鞋經常使用的都是前兩種方式,只有在不得不綁定context的狀況下才會使用第三種。其中,第三種方式,纔是函數調用的正確方式。瀏覽器

    foo().call(context,p1,p2);

    之因此,咱們在使用前兩種方式也能正常的運行,這其實就是一種語法糖而已,在js運行機制中,會把前兩種調方式,當作下面的方式進行處理閉包

    foo(p1, p2) 等價於  
    foo.call(undefined, p1, p2)
    
     obj.foo(p1, p2) 等價於
     obj.foo.call(obj, p1, p2)

    所以,若是咱們之後再調用函數時,能準確的找到context,就能夠惟一的確認this的值app

  3. this的使用場景
  • 3.1 全局環境使用函數

    不管是否在嚴格模式下,在全局執行環境中(在任何函數體外部)this 都指向全局對象。
    // 在瀏覽器中, window 對象同時也是全局對象:
    console.log(this === window); // true
    var a=1;
    console.log(this.a) //1
    console.log(window.a) //1
  • 3.2 普通函數中調用this

    在非嚴格模式下,且this的值沒有被調用函數設置,this 的值默認指向全局對象。
    funnction func(){
         console.log(this)
       }
       //瀏覽器環境中
       func()  // window
       //node環境中
       func()  // global
    在嚴格模式下,this的值若是不設置,就是是undefined
    funnction func(){
         "use strict"
         console.log(this)
       }
      func() === undefined; // true
  • 3.3 做爲對象中的方法調用prototype

    var obj={

    name:'我是對象obj',
        ofun:function(){
        console.log(this.name)
        }
    }
    var name='我是全局name';
    var func= obj.ofun;
    obj.ofun(); //我是對象obj
    func(); //我是全局name

    這裏有兩點須要注意:

    1.函數做爲對象的方法進行調用時,this指向當前的對象。                  
       2.對象中的函數方法名存儲的僅是一個函數的地址(地址中會有該函數的屬性:[[value]、[[writable]]、[[enumerable]]、[[congifable]])
       當把一個對象的方法賦值給另外一個變量(例如:func)時,引擎會將函數單獨保存在內存中,而後再將函數的地址賦值給foo屬性的value屬性。
  • 3.4 構造函數中使用

    this在構造函數中使用,值爲實例化的對象
    function Fun(name){
         this.name=name;
         this.speak=function(){
            console.log(this.name);
         }
       }
       var fun1=new Fun('jack');
       fun1.speak();
       var fun2=new Fun('rose');
       fun2.speak();//rose
  • 3.5 bind/call/apply

    this再被bind/call/apply強制綁定上下文執行環境時,屬於硬綁定。
    function foo(somerthing){
         console.log(this.a);
       }
       var obj={
         a:2
       }
       var bar = function(){
         foo.call(obj);
       };
       bar(); //2
       //硬綁定的bar不可能再修改它的this
       bar.call(window);//2
     }

    硬綁定的典型應用場景就是建立一個包裹函數,傳入全部的參數並返回接收到的全部值;

    function foo(somerthing){
         console.log(this.a,something);
         return this.a +something;
       }
       var obj={
         a:2
       }
       var bar = function(){
         return foo.apply(obj,arguments);
       };
       var b=bar(3);// 2 3
       console.log(b);//5

    因爲硬綁定是一種很是經常使用的模式,因此在ES5中提供了內置的方法Function.prototype.bind,它的用法以下;

    function foo(somerthing){
         console.log(this.a,something);
          return this.a +something;
       }
       var obj={
         a:2
       }
       var bar=foo.bind(obj);
       var b=bar(3);// 2 3
       console.log(b);//5

    call,apply,bind方法的區別:

  a:第一個參數都是要綁定的上下文執行環境,即this的值。
  b:均可在函數調用時傳遞參數。call,bind方法須要直接傳入,而apply方法須要以數組的形式傳入。
  c:call,apply方法是在調用以後當即執行函數,而bind方法沒有當即執行,須要將函數再執行一遍。有點閉包的味道。
  d:改變this對象的指向問題不只有call,apply,bind方法,也可使用that/self等變量來固定this的指向。

  • 3.6 回調函數中調用

    在回調函數中通常有兩種狀況:
       1. 回調函數爲匿名函數時,回調函數的this會指向window,須要對回調函數bind(this)。
       2. 回調函數爲箭頭函數時,回調函數的this會指向他的直接上層。
var obj = {
      name: "test for call-func",
      ofun: function(){
            //undefined 丟失
            setTimeout(function(){
              console.log(this.name)
            }, 100);
           //work well 硬綁定
            setTimeout(function(){
               console.log(this.name)
            }.bind(this), 100);//test for call-func
           // arrow function  test for call-func
           setTimeout( () => console.log(this.id), 100)
      }
    };

    obj.ofun();
  • 3.7 自執行函數
    自執行或者當即執行函數中的this指向Window
    首先自執行函數的幾種調用方式

    //常見的有兩種:
    (function(){})()    (function(){}())//w3c推薦方式
    //只有表達式才能被執行符號()執行
    +function test(){}();//+ - ! =等運算符可使前面的函數成爲表達式,加上後面()可當即執行。
    //函數聲明沒法當即執行一個函數,可是函數表達式能夠
    var a = function(){}();//這種是函數表達式,後面有()能夠當即執行。成爲一個當即執行函數。
    var obj = {
        number: 3,
        xxx: (function () {
            console.log(this + '--')//當即執行函數中的this指向window,由於當即執行函數是window調用的
            console.log(this.number + '~~~')//刪除上面一行,此處this.number返回undefined
            return function () {
                console.log(this.number + '】')
                this.number += 7;
                console.log(this + '+')
            }
        })()
    }
    
    obj.xxx() //至關於obj.xxx.call(),因此此處的this指向obj
    console.log(obj.number) //10
相關文章
相關標籤/搜索