1. 程式人生 > >改變函式作用域(call、 apply 、bind)

改變函式作用域(call、 apply 、bind)

call、 apply 、bind

  • 同異

    1)第一個引數都是this的上下文

    2)apply第二個引數是陣列,call和bind後面都是引數列表

    3) call和apply預設會自動執行,bind需要在後面加()來自動執行

    4)bind是ES5語法,它是新建立一個函式,然後把它的上下文繫結到bind()括號中的引數上,然後將它返回。

  • this 的指向
    this 永遠指向最後呼叫它的那個物件,箭頭函式則不是

        var name = "windowsName";
        var a = {
            name: "Cherry",
            fn: function
() {
console.log(name); // windowsName console.log(this.name); // Cherry } } a.fn();

fn 的內部的 this 是物件 a,因此 this.name 會找到 該函式內的變數 name
而name 前面沒有顯示的函式呼叫,其實它是 window.name 因此就會找到函式外的變數 name

   var name = "windowsName"; 
   var a = { 
       name: "Cherry"
, fn: function () { console.log(this.name); // Cherry } } var f = a.fn(); f;

雖然將 a 物件的 fn 方法賦值給變數 f 了,但是沒有呼叫,而,“this 永遠指向最後呼叫它的那個物件”, 所以最後是 window.f = window.a.fn() ,多層巢狀,只算最靠近方法的那層。所以 this 指向的是 a。

如何使用

        var name = 'hello';
        var
a = { name: "Cherry", fn: function (a, b) { console.log(this.name+":" +(a + b)); } } var b = a.fn; // 前三個輸出都是 Cherry: 3 b.bind(a, 1, 2)(); b.apply(a,[1,2]); b.call(a,1,2); b(); // hell0 NAN

第四個呼叫顯示了使用 call、 aply 、bind 之後,執行時 的this 由 window 變為 a ,即 a.fn(),為而第四個 任然是 window.fn()

箭頭函式的 this 始終指向函式定義時的 this,而非執行時。箭頭函式需要記著這句話:“箭頭函式中沒有 this 繫結,必須通過查詢作用域鏈來決定其值,如果箭頭函式被非箭頭函式包含,則 this 繫結的是最近一層非箭頭函式的 this,否則,this 為 undefined”。

建構函式繫結

使用call或apply方法,將父物件的建構函式繫結在子物件上

function Animal(){
    this.species = "動物";
  }
function Cat(name,color){
    Animal.apply(this, arguments);
    this.name = name;
    this.color = color;
  }
  
  var cat1 = new Cat("大毛","黃色");
  alert(cat1.species); // 動物

prototype模式

讓”貓”的prototype物件,指向一個Animal的例項,那麼所有”貓”的例項,就能繼承Animal了。

function Animal(){
    this.species = "動物";
  }
 function Cat(name,color){
    this.name = name;
    this.color = color;
  }
  alert(Cat.prototype.constructor.toString());
     // function Cat(name,color){
     //    this.name = name;
     //    this.color = color;
     // }   

      Cat.prototype = new Animal();
      var cat1 = new Cat('小H','小藍色');
      alert(cat1.species);  // 動物
      alert(Cat.prototype.constructor.toString());
     //  function Animal(){
     // this.species = "動物";
     //  }

      Cat.prototype.constructor = Cat;          alert(Cat.prototype.constructor.toString());
     // function Cat(name,color){
     //    this.name = name;
     //    this.color = color;
     // }  
      alert(cat1.species); // 動物

分析

"Cat.prototype = new Animal();
任何一個prototype物件都有一個constructor屬性,指向它的建構函式.Cat.prototype.constructor是指向Cat的;加了這一行以後,Cat.prototype.constructor指向Animal。也就是說,這行刪除了prototype 物件原先的值,然後賦予一個新值
這顯然會導致繼承鏈的紊亂(cat1明明是用建構函式Cat生成的),因此我們必須手動糾正,將Cat.prototype物件的constructor值改為Cat。"Cat.prototype.constructor = Cat"