成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

5分鐘帶你了解【前端裝飾器】,“高大上”的“基礎(chǔ)知識”

開發(fā) 前端
如果我們執(zhí)行一個方法,獲取返回值需要經(jīng)過一系列的計算,非常耗時間,那么我們可以判斷入?yún)ⅲ谝淮螘r計算完緩存起來,第二次的時候如果還是這個入?yún)ⅲ椭苯訌木彺嬷腥ツ茫@個操作也可以使用裝飾器去完成。

前言

大家好,我是林三心,用最通俗易懂的話講最難的知識點是我的座右銘,基礎(chǔ)是進(jìn)階的前提是我的初心。

基本介紹

裝飾器是一種以 @ 符號開頭的特殊語法,放在目標(biāo)代碼的前面用于包裝或擴展代碼功能。JavaScript 的裝飾器語法目前仍處于提案階段,現(xiàn)階段使用的話需要通過 bable 等方式進(jìn)行編譯之后,才能在瀏覽器正常運行。裝飾器分為兩種:類裝飾器,類成員裝飾器,分別用于裝飾我們的類以及類的成員。

基本使用(類裝飾器)

class MyClass {
  constructor() {}
}

比如現(xiàn)在有一個類或者函數(shù) MyClass,它的身上沒有任何的東西,但是我想要給他加一個 log 方法,那我們應(yīng)該怎么做呢?很多人回想說,直接在它身上加一個 log 方法即可~

class MyClass {
  constructor() {}
  
  log() {}
}

但是這么做的話,一個 class 是能做,那如果要給 1000 個 class 加上 log方法呢?那豈不是每一個都得寫~很麻煩,這個時候可以使用 裝飾器 去拓展每一個 class

  • 可以拓展原型方法
  • 可以拓展靜態(tài)屬性

裝飾器接收的參數(shù)是裝飾的目標(biāo)類,這里的 cls 就是 MyClass

function addConcole(target) {
  // 拓展原型方法
  target.prototype.log = function(msg) {
    console.log(`[${new Date()} ${msg}`);
  };
  // 拓展靜態(tài)屬性
  target.myName = '一個類'
  return target;
}

@addConcole
class MyClass {
  constructor() {}
}

const myObj = new MyClass();
myObj.log('林三心');
// [Sat Jul 08 2023 17:31:55 GMT+0800 (中國標(biāo)準(zhǔn)時間) 林三心
console.log(MyClass.myName)
// 一個類

應(yīng)用場景

Node路由請求Url(類成員裝飾器)

我們在使用一些 Node 的框架時,在寫接口的時候,我們可能會經(jīng)常看到這樣的代碼

  • 當(dāng)我們請求路徑是 GET doc 時會匹配到findDocById
  • 當(dāng)我們請求路徑是 POST doc 時會匹配到createDoc
class Doc {
  @Get('doc')
  async findDocById(id) {}
  
  @Post('doc')
  async createDoc(data) {}
}

其實這個 @Get 和 @Post ,是框架提供給我們的 類成員裝飾器,是的,類成員也能使用裝飾器,類成員裝飾器接收三個參數(shù):

  • target 是目標(biāo)類的原型對象
  • key 表示目標(biāo)類成員的鍵名
  • descriptor 是一個屬性描述符對象,它包含目標(biāo)類成員的屬性特性(例如 value、writable 等)
function Get(path) {
  return function(target, key, descriptor) {
    console.log({
      target,
      key,
      descriptor
    })
  }
}

圖片圖片

他的基本實現(xiàn)原理大概是這樣的

function Get(routePath) {
  return function(target, key, descriptor) {
    const originalMethod = descriptor.value; // 保存原始方法

    descriptor.value = function() {
      // 在原始方法執(zhí)行前加入邏輯
      console.log('處理 Get 請求,路由路徑: ' + routePath);

      // 執(zhí)行原始方法
      const result = originalMethod.apply(this, arguments);

      // 在原始方法執(zhí)行后加入邏輯
      console.log('Get 請求處理完成');

      return result;
    };

    return descriptor;
  };
}

接口權(quán)限控制(類成員裝飾器疊加)

上面我們介紹了一下 Nodejs Url 的路由匹配基本原理,但是這是不夠的,因為很多接口還需要權(quán)限控制,比如:

  • GET doc 接口只能 管理員 才能訪問
  • POST doc 接口只能 超級管理員 才能訪問

這也可以用裝飾器來實現(xiàn),并且裝飾器是可以疊加的~

class Doc {
  @Get('doc')
  @Role('admin')
  async findDocById(id) {}
  
  @Post('doc')
  @Role('superAdmin')
  async createDoc(data) {}
}

裝飾器疊加的執(zhí)行順序是 從下往上 的~我們可以看一下下面的例子,發(fā)現(xiàn)輸出順序是

  • 2
  • 1
function A () {
  console.log(1)
}
function B () {
  console.log(2)
}
class Doc {
  @A
  @B
  async test() {}
}

至于權(quán)限控制的裝飾器實現(xiàn),需要根據(jù)不同業(yè)務(wù)去實現(xiàn),我這里就粗略實現(xiàn)一下

function Role(permissions) {
  return function(target, key, descriptor) {
    const originalMethod = descriptor.value; // 保存原始方法

    descriptor.value = function() {
      // 在原始方法執(zhí)行前進(jìn)行權(quán)限驗證
      const user = getCurrentUser(); // 獲取當(dāng)前用戶信息

      // 檢查用戶是否擁有所需權(quán)限
      const hasPermission = checkUserPermissions(user, permissions);

      if (!hasPermission) {
        // 如果用戶沒有權(quán)限,則拋出錯誤或執(zhí)行其他處理
        throw new Error('無權(quán)限訪問該接口');
      }

      // 執(zhí)行原始方法
      const result = originalMethod.apply(this, arguments);

      return result;
    };

    return descriptor;
  };
}

記錄日志的裝飾器

我們想要在執(zhí)行某個函數(shù)的時候,記錄一下

  • 函數(shù)調(diào)用時間
  • 函數(shù)調(diào)用參數(shù)

這個時候我們也可以使用裝飾器來完成,非常方便!!!

// 日志裝飾器函數(shù)
function logDecorator(target, key, descriptor) {
  const originalMethod = descriptor.value; // 保存原始方法

  descriptor.value = function(...args) {
    console.log(`調(diào)用函數(shù):${key}`);
    console.log(`參數(shù):${JSON.stringify(args)}`);

    // 執(zhí)行原始方法
    const result = originalMethod.apply(this, args);

    console.log(`返回值:${result}`);

    return result;
  };

  return descriptor;
}

// 示例類
class Example {
  @logDecorator
  greet(name) {
    return `Hello, ${name}!`;
  }
}

// 測試
const example = new Example();
example.greet('林三心');

緩存的裝飾器

如果我們執(zhí)行一個方法,獲取返回值需要經(jīng)過一系列的計算,非常耗時間,那么我們可以判斷入?yún)ⅲ谝淮螘r計算完緩存起來,第二次的時候如果還是這個入?yún)ⅲ椭苯訌木彺嬷腥ツ茫@個操作也可以使用裝飾器去完成

// 緩存裝飾器函數(shù)
function cacheDecorator(target, key, descriptor) {
  const cache = {}; // 緩存對象

  const originalMethod = descriptor.value; // 保存原始方法

  descriptor.value = function(...args) {
    const cacheKey = JSON.stringify(args); // 生成緩存鍵

    if (cacheKey in cache) {
      console.log('從緩存中獲取結(jié)果');
      return cache[cacheKey]; // 直接返回緩存結(jié)果
    }

    // 執(zhí)行原始方法
    const result = originalMethod.apply(this, args);

    console.log('將結(jié)果緩存起來');
    cache[cacheKey] = result; // 緩存結(jié)果

    return result;
  };

  return descriptor;
}

// 示例類
class Example {
  @cacheDecorator
  getValue(key) {
    console.log('執(zhí)行函數(shù)邏輯');
    return key + Math.random(); // 模擬復(fù)雜的計算邏輯
  }
}

// 測試
const example = new Example();
console.log(example.getValue('foo'));
console.log(example.getValue('foo')); // 從緩存中獲取結(jié)果

防抖節(jié)流的裝飾器

對于防抖節(jié)流,我們平時可能會這么去做

class C {
  onClick = debounce(fn, 100)
}

但是這么做的話會使這個函數(shù)不好拓展,所以使用裝飾器真的很方便

// 防抖裝飾器
function debounce(time) {
  return function (target, key, descriptor) {
    const oldFunction = descriptor.value;
    let timer = null;
    descriptor.value = function () {
      clearTimeout(timer);
      timer = setTimeout(() => {
        oldFunction.apply(this, arguments)
      }, time);
    };
    return descriptor;
  }
}

// 節(jié)流裝飾器
function throttle(time) {
  return function (target, key, descriptor) {
    const oldFunction = descriptor.value;
    let isLock = false;
    descriptor.value = function() {
      if(isLock) { return; }
      isLock = true;
      oldFunction.apply(this, arguments);
      setTimeout(() => {
        isLock = false; 
      }, time);
    }
    return descriptor;
  }
}

class C {
  @debounce(1000)
  onClick() {}
  
  @throttle(1000)
  onScroll() {}
}


責(zé)任編輯:武曉燕 來源: 前端之神
相關(guān)推薦

2021-01-06 05:23:15

ServiceMesh網(wǎng)絡(luò)阿帕網(wǎng)

2019-12-24 09:10:43

Ipv6IP址協(xié)議

2019-07-18 16:32:06

Python函數(shù)數(shù)據(jù)

2018-02-01 14:15:00

Python函數(shù)

2021-10-19 07:27:08

HTTP代理網(wǎng)絡(luò)

2020-10-13 18:22:58

DevOps工具開發(fā)

2019-11-22 11:10:26

區(qū)塊鏈技術(shù)

2019-11-25 09:44:21

IPv6地址網(wǎng)絡(luò)

2020-10-14 11:31:41

Docker

2020-09-14 11:30:26

HTTP3運維互聯(lián)網(wǎng)

2022-06-02 08:46:04

網(wǎng)卡網(wǎng)絡(luò)服務(wù)器

2021-04-30 16:23:58

WebRTC實時音頻

2024-08-13 11:13:18

2020-02-19 19:26:27

K8S開源平臺容器技術(shù)

2020-11-23 16:23:59

CSS設(shè)計技術(shù)

2024-02-22 07:37:37

對象JVM內(nèi)存

2021-01-27 18:15:01

Docker底層宿主機

2024-11-07 16:09:53

2020-03-08 16:45:58

數(shù)據(jù)挖掘學(xué)習(xí)數(shù)據(jù)量

2009-08-02 12:21:22

服務(wù)器雙核處理器
點贊
收藏

51CTO技術(shù)棧公眾號

主站蜘蛛池模板: 国产精品久久久久久久久久久久久 | 国产成人免费视频网站高清观看视频 | 亚洲精彩视频在线观看 | 国产小u女发育末成年 | 日韩免费高清视频 | 伊人99| 日本成人三级电影 | 视频在线一区 | 我爱操| 日韩三级在线观看 | 成人久久久久久久久 | 国产在线精品一区二区三区 | 欧美a在线 | 精精国产xxxx视频在线播放 | 日韩欧美一区二区三区免费看 | 精品久久久久久久久久久久久久 | 国产91丝袜在线播放 | 亚洲国产一区在线 | 久久久久久亚洲 | 久干网 | 精品国产乱码一区二区三区a | 欧美性生活免费 | 久久综合久色欧美综合狠狠 | 午夜精品一区 | av在线播放免费 | 精品国产免费一区二区三区五区 | 少妇一级淫片免费播放 | 日韩在线观看中文字幕 | 国产精品一区在线 | 中文字幕亚洲一区二区三区 | 亚洲成人三级 | 日韩中字幕| 国产成人一区二区三区电影 | 欧美综合视频在线 | 精品久久99 | 波多野结衣亚洲 | 作爱视频免费看 | 国产亚洲二区 | 国产欧美日韩一区 | 国产精品美女久久久久aⅴ国产馆 | 欧美在线视频一区二区 |