js的call和this指向系列

在我理解call主要有2層意思

  • 實現繼承:

    • 繼承屬性和方法

      function Fun1(sex) {
          this.sex = sex,
          this.say = function() {
              console.log(this.sex);
          }
      }
      
      function Fun2(sex) {
          //this.sex = 'female';// #1
          Fun1.call(this, sex);
          //this.sex = 'female';// #2
      }
      
      var f2 = new Fun2("male");
      f2.say();// male

      (1) 以上Fun2繼承了Fun1的所有屬性和方法,所以Fun2的實例f2可以調用say方法輸出male。 (2) 如果僅取消註釋#1,將輸出male,如果僅取消註釋#2,將輸出female,請體會其中區別

    • 組合繼承

      function A() {
         this.name = 'a'
      }
      
      A.prototype = {
         say() {
             console.log(this.name)
         }
      }
      
      function B() {
         A.call(this)// 構造函數繼承
      }
      
      B.prototype = Object.create(A.prototype)// 原型繼承
      B.prototype.constructor = B// 改變constructor指向
      
      var b = new B()
      
      b.say()// a
      console.log(b.constructor)// B
  • 改變this指向

    • 關於this

      var sex = 'male';
      function Foo() {
          console.log(this.sex);
      }
      Foo();// => male // 直接調用,Foo就是普通函數,所以Foo內部的this指向的就是全局(因爲函數本身也是掛載到window下面的),可以向上搜索到male
      Foo.call({sex: 'female'});// female // 同上,但是使用call改變this指向到了傳入的對象,所以輸出female
      var f = new Foo();// undefined // new關鍵字生成實例f,Foo就是構造函數,所以Foo內部的this指向實例f本身,f是沒有sex這個屬性的,輸出undefined
      var a = 10
      
      function foo() {
          a = 100
          console.log(a)
          console.log(this.a)// 被當做普通函數調用,this指向全局)
          var a// 變量提升
      }
      foo()// 100 10
    • 簡單示例

      function Fun1() {
          this.sex= "male",
          this.say = function() {
              console.log(this.sex);
          }
      }
      
      function Fun2() {
          this.sex= "female";
      }
      
      var f1 = new Fun1();
      var f2 = new Fun2();
      
      f1.say();// male
      f1.say.call(f2);// female // f1.say調用時的this指向被改成了指向f2,所以輸出**female**(注意這裏並不是繼承,f2也沒有say這個方法,f2.say()是會報錯的)
    • 深入示例

      function foo(cb) {
          var self = this;
          this.sex = 'male';
          setTimeout(function() {
              cb && cb.call(self, 22);// 在這裏調用回調函數cb時,this指向foo這個構造函數本身
          })
      }
      var f = new foo(function(age) {
          console.log(this.sex, age);// male 22
      })
      function Foo() {
          this.sex = 'male';
          this.say = function() {
              setTimeout(function() {
                  console.log(this.sex);// 定時器普通回調函數中的this指向window
              }, 0)
          }
          this.speak = function() {
              setTimeout(() => {
                  console.log(this.sex);// 箭頭函數沒有自己的this,它的this繼承自外部函數的作用域。所以,定時器箭頭回調函數中的this指向構造函數Foo本身
              }, 0)
          }
      }
      var f = new Foo()
      f.say()// undefined
      f.speak()// male

call和apply的區別

  • call([thisObj[, arg1[, arg2[, …[, argN]]]]])
  • apply([thisObj[, argArray]])

參考文章

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章