<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      Web前端入門第 67 問:JavaScript 中的面向?qū)ο缶幊?/span>

      對象 非彼對象啊,不要理解錯了哦~~

      面向?qū)ο缶幊?/code> 這個概念在 Java 編程語言中用得比較多,JS 同時支持 面向?qū)ο缶幊?/code> 和 函數(shù)式編程

      像大名鼎鼎的 ReactVue 他們都有兩種開發(fā)風(fēng)格,比如:

      Vue 中的 組合式API選項式API 也是兩種編程模式的代表。

      React 中的 函數(shù)式組件類組件 就是兩種編程模式的代表。

      原型鏈

      JS 中的每個對象(null 除外)都有一個隱式原型,可以通過 __proto__ 或者 Object.getPrototypeOf() 訪問。

      null 雖然用 typeof 檢測會獲得 Object 類型,但 null 有一點特殊,表示空,什么都沒有的意思。

      比如:

      const a = 'str'
      console.log(a.__proto__) // 獲得 String.prototype
      console.log(Object.getPrototypeOf(a)) // 獲得 String.prototype
      console.log(a.__proto__ === String.prototype) // true
      console.log(Object.getPrototypeOf(a) === String.prototype) // true
      

      這么多年的搬磚經(jīng)驗來看,__proto__ 這個屬性能派上用場的場景真的少見~~

      構(gòu)造函數(shù)

      function 申明的函數(shù)都擁有一個顯式原型 prototype 屬性,如果用 new 關(guān)鍵字調(diào)用這個函數(shù),那么此時這個函數(shù)就稱之為 構(gòu)造函數(shù)

      實例化構(gòu)造函數(shù)的時候,實例化對象的 __proto__ 就指向構(gòu)造函數(shù)的 prototype 屬性。

      function Person() {}
      Person.prototype.name = '前端路引'
      
      const person = new Person()
      
      console.log(person.__proto__ === Person.prototype) // true
      console.log(person.name) // 輸出:前端路引
      

      編程實踐推薦:構(gòu)造函數(shù)聲明時,首字母一般大寫,而函數(shù)聲明時首字母一般小寫

      繼承

      繼承 這玩意兒可以算作面向?qū)ο缶幊痰暮诵乃枷耄绻幊陶Z言不支持 繼承,那面向?qū)ο缶褪且痪淇赵挕?/p>

      JS 中的繼承玩法多種多樣,掌握一種就可以獨步武林~~ 但面試官可是全能高手,一般都會問知道有幾種繼承方式,他們怎么實現(xiàn)這些問題。

      原型鏈繼承

      子類通過 prototype 指向父類實例,就是原型鏈繼承,但此種方式繼承有一個大缺陷,會共享父類中的引用類型(比如數(shù)組、對象)。

      function Parent() {
        // 父類中申明的屬性
        this.arr = ['公眾號', '前端路引'];
      }
      
      // 父類中申明的方法
      Parent.prototype.getName = function () {
        console.log('前端路引');
      }
      
      function Child() {}
      // 使用原型鏈繼承父類
      Child.prototype = new Parent();
      
      const child1 = new Child();
      // 修改 child1 的實例屬性
      child1.arr.push(1);
      child1.getName();
      
      const child2 = new Child();
      child2.getName();
      console.log(child2.arr); // 輸出:['公眾號', '前端路引', 1]
      

      可以看到子類都可以調(diào)用父類的 getName 方法,但是在 child1 實例修改 arr 屬性后,child2 也會受影響,這邊是原型鏈繼承中的弊端。

      構(gòu)造函數(shù)繼承

      此繼承方式的特點是利用函數(shù)的 call 或者 apply 方法,再傳入子類的 this 指針實現(xiàn)繼承,缺點是無法繼承父類上的原型方法。

      function Parent(name) {
        this.name = name;
        this.arr = ['公眾號', '前端路引'];
        this.test = function () {
          console.log('調(diào)用父類 test 方法');
        }
      }
      Parent.prototype.getName = function () {
        console.log(this.name);
      }
      
      function Child(name) {
        Parent.call(this, name);
      }
      
      const child1 = new Child('前端路引');
      // 修改 child1 的實例屬性
      child1.arr.push(1);
      console.log(child1.arr); // ['公眾號', '前端路引', 1]
      child1.test(); // 輸出:調(diào)用父類 test 方法
      
      const child2 = new Child('前端路引');
      console.log(child2.arr); // ['公眾號', '前端路引']
      child2.getName(); // 報錯  TypeError: child2.getName is not a function
      

      此繼承方式修復(fù)了 原型鏈繼承 中共享 引用類型 問題,但卻存在無法繼承父類原型鏈方法的弊端。

      組合繼承

      此繼承方式結(jié)合了原型鏈繼承和構(gòu)造函數(shù)繼承而衍生出的另一種繼承方式,同時解決了兩種繼承方式的弊端。

      function Parent(name) {
        this.name = name;
        this.arr = ['公眾號', '前端路引'];
        this.test = function () {
          console.log('調(diào)用父類 test 方法');
        }
      }
      Parent.prototype.getName = function () {
        console.log(this.name);
      }
      
      function Child(name) {
        Parent.call(this, name); // 繼承屬性(第二次調(diào)用)
      }
      Child.prototype = new Parent(); // 繼承方法(第一次調(diào)用)
      
      const child1 = new Child('前端路引');
      // 修改 child1 的實例屬性
      child1.arr.push(1);
      console.log(child1.arr); // ['公眾號', '前端路引', 1]
      child1.test(); // 輸出:調(diào)用父類 test 方法
      
      const child2 = new Child('前端路引');
      console.log(child2.arr); // ['公眾號', '前端路引']
      child2.getName(); // 輸出:前端路引
      

      組合繼承可以擁有父類上的 getName,同時還不會共享父類上的引用類型,但父類構(gòu)造函數(shù)卻被調(diào)用了兩次,存在性能優(yōu)化上的空間,這也是此種繼承方式的弊端。

      寄生組合繼承

      此繼承方式通過 Object.create 方法復(fù)制父類的原型鏈,優(yōu)化父類會被調(diào)用兩次問題,算是比較完美的一種繼承方式,不存在性能浪費。

      function Parent(name) {
        this.name = name;
        this.arr = ['公眾號', '前端路引'];
        this.test = function () {
          console.log('調(diào)用父類 test 方法');
        }
      }
      Parent.prototype.getName = function () {
        console.log(this.name);
      }
      
      function Child(name) {
        Parent.call(this, name); // 繼承屬性(第二次調(diào)用)
      }
      Child.prototype = Object.create(Parent.prototype); // 繼承原型
      Child.prototype.constructor = Child; // 修復(fù)子類的 constructor 引用
      
      const child1 = new Child('前端路引');
      // 修改 child1 的實例屬性
      child1.arr.push(1);
      console.log(child1.arr); // ['公眾號', '前端路引', 1]
      child1.test(); // 輸出:調(diào)用父類 test 方法
      
      const child2 = new Child('前端路引');
      console.log(child2.arr); // ['公眾號', '前端路引']
      child2.getName(); // 輸出:前端路引
      

      寄生組合繼承重點就是兩句代碼:

      Child.prototype = Object.create(Parent.prototype); // 繼承原型
      Child.prototype.constructor = Child; // 修復(fù)子類的 constructor 引用
      

      由于 Object.create 會復(fù)制父類的 constructor 屬性,導(dǎo)致子類的 constructor 屬性被重寫了,所以需要手動修復(fù)。

      在 ES6 出現(xiàn)之前,這種繼承已經(jīng)是 JS 面向?qū)ο缶幊讨械?strong>最優(yōu)解了。

      ES6 class 繼承

      ES6 出現(xiàn)了 class 類關(guān)鍵字,也多了 extends 繼承關(guān)鍵字,可以很方便的實現(xiàn)繼承。

      但其底層實現(xiàn)邏輯還是 寄生組合繼承,相當(dāng)于是提供了一種語法糖,簡化了寄生組合繼承中的代碼。

      class Parent {
        constructor(name) {
          this.name = name;
          this.arr = ['公眾號', '前端路引'];
        }
        test () {
          console.log('調(diào)用父類 test 方法');
        }
        getName () {
          console.log(this.name);
        }
      }
      
      class Child extends Parent {
        constructor(name) {
          super(name); // 必須有此行
        }
      }
      
      const child1 = new Child('前端路引');
      // 修改 child1 的實例屬性
      child1.arr.push(1);
      console.log(child1.arr); // ['公眾號', '前端路引', 1]
      child1.test(); // 輸出:調(diào)用父類 test 方法
      
      const child2 = new Child('前端路引');
      console.log(child2.arr); // ['公眾號', '前端路引']
      child2.getName(); // 輸出:前端路引
      

      如果沒有 super() 這行代碼,JS 解析器會報錯:

      ReferenceError: Must call super constructor in derived class before accessing 'this' or returning from derived constructor
      

      意思就是在父類訪問 this 之前,子類中必須調(diào)用 super() 方法。

      原型鏈查找規(guī)則

      有了父子兩層繼承關(guān)系,那肯定就有更多層次的繼承關(guān)系,比如:

      class A {}
      
      class B extends A {}
      
      class C extends B {}
      

      在這種多層級的繼承關(guān)系中,JS 的原型鏈查找規(guī)則永遠(yuǎn)都是一層一層往上找,終點是找到 Object.prototype 為止,如果還找不到就報錯。

      比如:

      class A {}
      class B extends A {}
      class C extends B {}
      
      const child = new C();
      console.log(child.toString())
      console.log(child.test()) // 報錯  TypeError: child.test is not a function
      

      以上代碼中 A、B、C 都沒有 toString 方法,但是實例 child 卻可以調(diào)用,原因就是 child 的原型鏈最終找到了 Object.prototype.toString 方法。

      test 直到 Object.prototype 為止都沒找到,所以最終報錯。

      可以理解其查找規(guī)則是這樣的:

      實例 (obj) --> 構(gòu)造函數(shù).prototype --> 父構(gòu)造函數(shù).prototype --> ... --> Object.prototype --> null
      

      寫在最后

      雖然個人更喜歡 函數(shù)式編程 方式,但面向?qū)ο筮@種寫法也必須要掌握,要不然看到面向?qū)ο蟮拇a,就玩完了~~

      posted @ 2025-06-20 10:32  前端路引  閱讀(544)  評論(0)    收藏  舉報
      主站蜘蛛池模板: 香港日本三级亚洲三级| 国产精品久久国产精品99 gif| 一道本AV免费不卡播放| 亚洲一区二区三区自拍天堂| 中文字幕精品人妻av在线 | 日本一区二区三区专线| 高h纯肉无码视频在线观看| 91久久夜色精品国产网站| 神马久久亚洲一区 二区| 久久乐国产精品亚洲综合| 亚洲 欧美 影音先锋| 久久一亚色院精品全部免费| 粉嫩一区二区三区精品视频| 放荡的少妇2欧美版| 亚洲第一极品精品无码久久| 又大又粗欧美成人网站| 94人妻少妇偷人精品| 欧美性xxxxx极品少妇| 人妻系列中文字幕精品| 亚洲无人区视频在线观看| 欧美精品一区二区三区中文字幕| 国产精品福利中文字幕| 日本免费人成视频在线观看| 国内精品无码一区二区三区| 朔州市| 成人国产亚洲精品一区二区| 亚洲日本欧美日韩中文字幕| 国产一区二区三区小说| 国产va免费精品观看| 色悠悠国产精品免费观看| 亚洲av一本二本三本| 日本污视频在线观看| 久久亚洲av成人一二三区| 久久精品人人做人人爽97| 成人午夜在线观看日韩| 国产色悠悠视频在线观看| 亚洲色欲色欲www在线看| 亚洲精品日韩在线观看| 亚洲女同性同志熟女| 377P欧洲日本亚洲大胆| 久久香蕉欧美精品|