this與new、call、apply、bind的關係

weixin_34124651發表於2018-06-23

什麼是this

this的指向在函式定義的時候是確定不來的,只有函式執行的時候,才能確定。
this的最終指向是那個呼叫它的物件,確切的說,是它的上級父物件,父物件有可能包含在其他物件中。
示例:

    <script>
        var name = "tom";
        function M() {
            console.log(this);
        }
        M();    // window
        var o1 = {
            name: 'o1',
            fun: M
        }
        o1.fun();  // o1
        var o2 = {
            name: 'o2',
            o3 : {
                name: 'o3'
            }
        }
        o2.o3.fun = M;
        o2.o3.fun();    // o3
    </script>

對於建構函式中的this

在《原型鏈》中我們提到過new的本質:

  1. 建立一個空物件o,o繼承自建構函式原型
  2. 執行建構函式,指定執行上下文為o,使o獲取到建構函式的屬性和方法
  3. 判斷執行建構函式的返回,如果是物件則返回該物件,否則返回o
    示例:
function newObject(func) {
  var o = Object.create(func.prototype);
  var k = func.call(o);
  if (typeof(k) === 'object'&&k !== null) {
    return k;
  } else {
    return o;
  }
}

Object.create()方法建立一個新物件,使用現有的物件來提供新建立的物件的__proto__
這裡引出一個知識點:

  1. 在new的語法中,例項物件賦值給誰,this指向的就是誰,確切的說,其實this指向的是示例中的o或k,具體看返回
  2. 當建構函式中this碰到return,跟示例中一樣,如果返回型別是個物件(k),那麼this就指向這個新物件,否則返回指向函式的例項(o)
    示例:
    <script>
        function M1() {
            return {
                name: 'M1'
            }
        }
        function M2() {
            return 1;
        }
        function M3() {
            return null;
        }
        var m1 = new M1();  // {name: 'M1'}
        var m2 = new M2();  // M2
        var m3 = new M3();  // M3,雖然typeof null='object',但是在這裡this還是指向那個函式的例項,因為null比較特殊
    </script>

call、apply、bind

相同點:

  • 接收多個引數
  • 改變了函式執行時this指向,指向為第一個入參物件

不同點:

  • call、apply會立即執行函式,bind不執行,返回新的函式物件,需呼叫
  • call、bind支援從第二個引數開始傳多個引數,apply只傳兩個引數,除第一個指定物件外還可以傳一個陣列形式的引數
    示例:
    <script>
        var name = 'joe'
        function M(job, age) {
            console.log(this.name, job, age);
        }
        var o = {
            name: 'tom', job: 'student', age: 17
        }
        M('rose', 16);                      // joe rose 16
        M.call(o, o.job, o.age);            // tom student 17
        M.apply(o, [o.job, o.age]);         // tom student 17
        var f = M.bind(o, o.job, o.age);    // tom student 17
        function K(job, age) {
            var o1 = {name: 'lilei'}
            M.apply(o, arguments);
        }
        K(o.job, o.age);                    // tom student 17
    </script>

相關文章