1. 程式人生 > 其它 >this指向 箭頭函式 普通函式

this指向 箭頭函式 普通函式

this指向

哪個物件呼叫函式,函式裡面的this指向哪個物件。

  let name = 'tom'
  function a(){
      let name = 'jerry';
      console.log(this.name)
  }
  let obj = {
      name: 'mark',
      fun: function(){
          let name = 'james'
          console.log(this.name)
      }
  }
  // 呼叫
  a()         //  window.a()  undefined
  obj.fun()   //  obj.fun()   mark

  /**
   *  this.name 是某個物件中的 name 屬性,而不是函式中的變數 name,注意區分
   **/

稍微特殊一點的,但還是可以用上面那一句話解釋

  let obj1={
      name: "tom"
  }
  let obj2={
      name: "jerry",
      fun:function(){
          console.log(this.name);
      }
  }
  obj1.fun = obj2.fun;
  obj1.fun();          //111
/***
  上面的賦值就等價:
  let obj1={
      name: "tom",
      fun:function(){
          console.log(this.name);
      }
  }
***/

建構函式

  function Person(){
      this.name = 'person'
  }
  let person = new Person()
  let tom = new Person()
  tom.name = 'tom'
  let jerry = new Person()
  jerry.name = 'jerry'

  console.log(tom.name)        // tom
  console.log(jerry.name)      // jerry
  console.log(person.name)     // person

箭頭函式和普通函式的區別如下:

普通函式:根據呼叫我的人(誰呼叫我,我的this就指向誰)

箭頭函式:根據所在的環境(我再哪個環境中,this就指向誰)

實現apply, call, bind函式

call 實現

  Function.prototype.myCall = function(context){  
    // 儲存傳進來的引數
    context = context || window;
    // 儲存呼叫函式本身的屬性和方法
    context.invokeFun = this;
    // 獲取傳進來物件的屬性和方法
    let args = [...arguments].slice(1);
    // 將兩個儲存再一起
    let result = context.invokeFun(...args);
    // 刪除防止汙染作用域
    delete context.invokeFun;
    // 現在這個result我理解為 a.call(b) ,是a, b兩個的集合,返回這個集合
    return result;
  }

  let obj = {
    name: 'tom',
    age: 22,
    fun: function(){
      console.log('我是object中的函式');
    }
  }

  function my(){
    this.gender = 'male';
    console.log(this.name+','+this.age+","+this.gender);
    this.fun();
  }

  my.myCall(obj);
  /**
  *  輸出:  tom,22,male
  *         我是object中的函式
  **/
  my();
  /**
  *  輸出:  undefined,undefined,male
  *         Uncaught TypeError: this.fun is not a function
  **/

我的理解就是將兩個物件的屬性和方法儲存再一個物件中然後再返回。
在補充一下arguments是將函式傳入的引數以類似陣列的形式儲存。

  function foo(a, b, c){
    let name = a;
    let age = b;
    let gender = c;
    console.log(arguments);
  }

  foo('tom', 12, 'male');
  // 輸出: ['tom', 12, 'male']

歡迎指正,嘿嘿嘿^ ^。
** apply 實現 **
call 和 apply 一樣,只是引數不同

   Function.prototype.myApply = function(context){  
    // 儲存傳進來的引數
    context = context || window;
    // 儲存呼叫函式本身的屬性和方法
    context.invokeFun = this;
    // 獲取傳進來物件的屬性和方法
    let result;
    if(arguments[1]){
      result = context.invokeFun(...arguments[1])
    }else{
      result = context.invokeFun()
    }
    // 刪除防止汙染作用域
    delete context.invokeFun;
    // 現在這個result我理解為 a.call(b) ,是a, b兩個的集合,返回這個集合
    return result;
  }

  let obj = {
    name: 'tom',
    age: 22,
    fun: function(){
      console.log('我是object中的函式');
    }
  }

  function my(){
    this.gender = 'male';
    console.log(this.name+','+this.age+","+this.gender);
    this.fun();
  }

  my.myApply(obj);
  /**
  *  輸出:  tom,22,male
  *         我是object中的函式
  **/
  my();
  /**
  *  輸出:  undefined,undefined,male
  *         Uncaught TypeError: this.fun is not a function
  **/

bind 實現

bind()方法建立一個新的函式, 當被呼叫時,將其this關鍵字設定為提供的值。
當使用new 操作符呼叫繫結函式時,該引數無效。

   Function.prototype.myBind = function(context){
    // 獲取除了一個引數以外的所有引數
    let args = [...arguments].slice(1);
    // 定義一個函式,用於下面判斷是否使用 new 操作符繫結該函式
    F = function(){};
    // 此處的 this 指呼叫函式,即 a.bind(obj) 中的 a
    self = this;
    // 因為 bind 被呼叫時並不是立即執行
    // 而是建立一個新函式
    // 當新函式被執行時, 用 call 就可以了
    bound = function(){
        let finalArgs = [...args, ...arguments];
        // 下面的 this 是指用 new 例項化出的物件
        return self.call((this instanceof F ?  this:context),     finalArgs)
        }

        F.prototype = self.prototype;
        bound.prototype = new F()

        return bound;
    }

    function my(){
        console.log(this.name);
    }

    let obj = {
        name: 'rbt'
    }

    let temp = my.myBind(obj);

    temp() // rbt

參考(侵刪):