最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

JavaScript實現(xiàn)函數(shù)執(zhí)行攔截的多種方法

 更新時間:2025年06月22日 13:43:41   作者:北辰alk  
函數(shù)執(zhí)行攔截是JavaScript中強(qiáng)大的元編程技術(shù),可以實現(xiàn)日志記錄、性能監(jiān)控、權(quán)限控制等功能,本文將深入探討多種函數(shù)攔截方法,從基礎(chǔ)到高級,幫助您全面掌握這一技術(shù),需要的朋友可以參考下

1. 基礎(chǔ)攔截方法

1.1 函數(shù)包裝(最簡單的攔截方式)

function originalFunction(a, b) {
  console.log('執(zhí)行原始函數(shù)');
  return a + b;
}

// 創(chuàng)建包裝函數(shù)實現(xiàn)攔截
function createInterceptor(originalFn) {
  return function(...args) {
    console.log(`函數(shù)被調(diào)用,參數(shù): ${args}`);
    const start = performance.now();
    
    try {
      const result = originalFn.apply(this, args);
      console.log(`函數(shù)返回: ${result}`);
      return result;
    } catch (error) {
      console.error(`函數(shù)拋出異常: ${error}`);
      throw error;
    } finally {
      const duration = performance.now() - start;
      console.log(`函數(shù)執(zhí)行耗時: ${duration}ms`);
    }
  };
}

const interceptedFn = createInterceptor(originalFunction);
interceptedFn(2, 3); // 輸出調(diào)用日志和結(jié)果

1.2 對象方法攔截

const obj = {
  value: 10,
  add(x) {
    return this.value + x;
  }
};

// 攔截對象方法
function interceptMethod(obj, methodName) {
  const original = obj[methodName];
  
  obj[methodName] = function(...args) {
    console.log(`攔截方法 ${methodName} 調(diào)用`);
    return original.apply(this, args);
  };
}

interceptMethod(obj, 'add');
obj.add(5); // 輸出: "攔截方法 add 調(diào)用" 然后返回15

2. 高級攔截技術(shù)

2.1 使用Proxy實現(xiàn)全面攔截

const target = {
  id: 42,
  compute(a, b) {
    return a * b;
  }
};

const handler = {
  // 攔截函數(shù)調(diào)用
  apply(target, thisArg, argumentsList) {
    console.log(`調(diào)用函數(shù): ${target.name}`, argumentsList);
    const result = Reflect.apply(target, thisArg, argumentsList);
    console.log(`函數(shù)返回: ${result}`);
    return result;
  },
  
  // 攔截屬性訪問
  get(target, prop, receiver) {
    const value = Reflect.get(target, prop, receiver);
    if (typeof value === 'function') {
      return new Proxy(value, handler); // 對方法返回新代理
    }
    return value;
  }
};

const proxy = new Proxy(target, handler);
proxy.compute(6, 7); // 輸出調(diào)用日志和結(jié)果

2.2 基于裝飾器的攔截(ES2016+)

// 類方法裝飾器
function logExecution(target, name, descriptor) {
  const original = descriptor.value;
  
  descriptor.value = function(...args) {
    console.log(`調(diào)用方法 ${name} 參數(shù):`, args);
    try {
      const result = original.apply(this, args);
      console.log(`方法 ${name} 返回:`, result);
      return result;
    } catch (error) {
      console.error(`方法 ${name} 出錯:`, error);
      throw error;
    }
  };
  
  return descriptor;
}

class Calculator {
  @logExecution
  add(a, b) {
    return a + b;
  }
}

const calc = new Calculator();
calc.add(2, 3); // 輸出調(diào)用日志和結(jié)果

3. 應(yīng)用場景實現(xiàn)

3.1 性能監(jiān)控攔截器

function createPerformanceInterceptor(fn, metricName) {
  return function(...args) {
    const start = performance.now();
    const memoryBefore = process.memoryUsage().heapUsed;
    
    try {
      const result = fn.apply(this, args);
      const duration = performance.now() - start;
      const memoryAfter = process.memoryUsage().heapUsed;
      
      console.log(`[Metrics] ${metricName} - 耗時: ${duration.toFixed(2)}ms`);
      console.log(`[Metrics] ${metricName} - 內(nèi)存變化: ${((memoryAfter - memoryBefore) / 1024).toFixed(2)}KB`);
      
      return result;
    } catch (error) {
      console.error(`[Metrics] ${metricName} - 執(zhí)行失敗`);
      throw error;
    }
  };
}

// 使用示例
const monitoredFn = createPerformanceInterceptor(heavyCalculation, 'heavyCalculation');
monitoredFn(/* 參數(shù) */);

3.2 權(quán)限控制攔截器

function createAuthInterceptor(fn, requiredRole) {
  return function(...args) {
    const user = getCurrentUser(); // 假設(shè)有獲取當(dāng)前用戶的函數(shù)
    
    if (!user || !user.roles.includes(requiredRole)) {
      throw new Error(`無權(quán)訪問此功能,需要角色: ${requiredRole}`);
    }
    
    console.log(`用戶 ${user.name} (${user.roles}) 調(diào)用受保護(hù)函數(shù)`);
    return fn.apply(this, args);
  };
}

// 使用示例
const adminOnlyFunction = createAuthInterceptor(deleteAllData, 'admin');
try {
  adminOnlyFunction();
} catch (error) {
  console.error(error.message);
}

4. 特殊函數(shù)攔截

4.1 構(gòu)造函數(shù)攔截

function interceptConstructor(OriginalClass) {
  return new Proxy(OriginalClass, {
    construct(target, args) {
      console.log(`創(chuàng)建 ${target.name} 實例,參數(shù):`, args);
      const instance = Reflect.construct(target, args);
      
      // 返回代理實例以攔截方法調(diào)用
      return new Proxy(instance, {
        get(target, prop) {
          const value = Reflect.get(target, prop);
          if (typeof value === 'function') {
            console.log(`調(diào)用實例方法 ${prop}`);
          }
          return value;
        }
      });
    }
  });
}

// 使用示例
class User {
  constructor(name) {
    this.name = name;
  }
  
  greet() {
    return `Hello, ${this.name}!`;
  }
}

const ProxiedUser = interceptConstructor(User);
const user = new ProxiedUser('Alice'); // 輸出構(gòu)造函數(shù)日志
user.greet(); // 輸出方法調(diào)用日志

4.2 異步函數(shù)攔截

function interceptAsync(fn) {
  return async function(...args) {
    console.log('異步函數(shù)開始執(zhí)行');
    try {
      const result = await fn.apply(this, args);
      console.log('異步函數(shù)成功完成');
      return result;
    } catch (error) {
      console.error('異步函數(shù)執(zhí)行失敗:', error);
      throw error;
    }
  };
}

// 使用示例
const originalAsync = async (delay) => {
  await new Promise(resolve => setTimeout(resolve, delay));
  return '完成';
};

const interceptedAsync = interceptAsync(originalAsync);
interceptedAsync(1000).then(console.log);

5. 高級應(yīng)用:AOP實現(xiàn)

5.1 面向切面編程基礎(chǔ)實現(xiàn)

// 切面注冊表
const aspectRegistry = new Map();

// 注冊切面
function registerAspect(fnName, { before, after, around, onError }) {
  aspectRegistry.set(fnName, { before, after, around, onError });
}

// 應(yīng)用切面
function applyAspects(obj) {
  for (const [name, method] of Object.entries(obj)) {
    if (typeof method === 'function' && aspectRegistry.has(name)) {
      const aspects = aspectRegistry.get(name);
      obj[name] = createAspectWrapper(method, aspects);
    }
  }
}

function createAspectWrapper(original, aspects) {
  return function(...args) {
    try {
      // 前置通知
      if (aspects.before) aspects.before(args);
      
      // 環(huán)繞通知
      let result;
      if (aspects.around) {
        result = aspects.around(() => original.apply(this, args));
      } else {
        result = original.apply(this, args);
      }
      
      // 后置通知
      if (aspects.after) aspects.after(result);
      
      return result;
    } catch (error) {
      // 異常通知
      if (aspects.onError) aspects.onError(error);
      throw error;
    }
  };
}

// 使用示例
const service = {
  calculate(a, b) {
    return a + b;
  }
};

// 注冊切面
registerAspect('calculate', {
  before: (args) => console.log('計算開始,參數(shù):', args),
  after: (result) => console.log('計算完成,結(jié)果:', result)
});

// 應(yīng)用切面
applyAspects(service);

service.calculate(2, 3); // 輸出切面日志

5.2 基于ES6 Proxy的AOP實現(xiàn)

function createAopProxy(target, aspects = {}) {
  return new Proxy(target, {
    get(target, prop) {
      const original = target[prop];
      
      if (typeof original === 'function') {
        return function(...args) {
          // 前置通知
          if (aspects.before) aspects.before(prop, args);
          
          try {
            // 環(huán)繞通知
            let result;
            if (aspects.around) {
              result = aspects.around(prop, () => original.apply(target, args));
            } else {
              result = original.apply(target, args);
            }
            
            // 后置通知
            if (aspects.after) aspects.after(prop, result);
            
            return result;
          } catch (error) {
            // 異常通知
            if (aspects.onError) aspects.onError(prop, error);
            throw error;
          }
        };
      }
      
      return original;
    }
  });
}

// 使用示例
const service = {
  add(a, b) { return a + b; },
  multiply(a, b) { return a * b; }
};

const proxiedService = createAopProxy(service, {
  before: (method, args) => console.log(`調(diào)用 ${method},參數(shù): ${args}`),
  after: (method, result) => console.log(`方法 ${method} 返回: ${result}`)
});

proxiedService.add(2, 3); // 輸出調(diào)用日志和結(jié)果
proxiedService.multiply(4, 5); // 輸出調(diào)用日志和結(jié)果

6. 注意事項與最佳實踐

性能考量

  • 避免在熱路徑(hot path)上使用復(fù)雜的攔截邏輯
  • 生產(chǎn)環(huán)境考慮移除不必要的攔截器
  • 使用performance.now()測量攔截開銷

調(diào)試技巧

  • 為攔截器添加唯一標(biāo)識便于調(diào)試
  • 保留原始函數(shù)引用以便直接調(diào)用
  • 使用console.trace()追蹤攔截調(diào)用棧

安全注意事項

  • 確保攔截器不會意外暴露敏感數(shù)據(jù)
  • 驗證攔截器中的權(quán)限檢查邏輯
  • 避免在攔截器中修改原始參數(shù)

最佳實踐

  • 保持?jǐn)r截邏輯單一職責(zé)
  • 為攔截器編寫單元測試
  • 文檔化攔截行為和使用方式

7. 現(xiàn)代JavaScript攔截方案

7.1 使用Reflect API

const handler = {
  apply(target, thisArg, argumentsList) {
    console.log(`調(diào)用: ${target.name}`, argumentsList);
    return Reflect.apply(target, thisArg, argumentsList);
  },
  construct(target, argumentsList, newTarget) {
    console.log(`構(gòu)造: ${target.name}`, argumentsList);
    return Reflect.construct(target, argumentsList, newTarget);
  }
};

function sum(a, b) { return a + b; }

const proxiedSum = new Proxy(sum, handler);
proxiedSum(2, 3); // 輸出調(diào)用日志

7.2 使用Async/Await攔截

function asyncInterceptor(target) {
  return async function(...args) {
    const start = Date.now();
    try {
      const result = await target.apply(this, args);
      console.log(`異步操作成功,耗時: ${Date.now() - start}ms`);
      return result;
    } catch (error) {
      console.error(`異步操作失敗,耗時: ${Date.now() - start}ms`, error);
      throw error;
    }
  };
}

// 使用示例
const originalFetch = fetch;
window.fetch = asyncInterceptor(originalFetch);

// 所有fetch調(diào)用都會被攔截
fetch('https://api.example.com/data')
  .then(response => response.json())
  .then(console.log);

8. 實際應(yīng)用案例

8.1 Redux中間件(函數(shù)攔截的典型應(yīng)用)

// 自定義Redux中間件
const loggerMiddleware = store => next => action => {
  console.groupCollapsed(`dispatching ${action.type}`);
  console.log('prev state:', store.getState());
  console.log('action:', action);
  
  const result = next(action);
  
  console.log('next state:', store.getState());
  console.groupEnd();
  
  return result;
};

// 應(yīng)用中間件
const store = createStore(
  rootReducer,
  applyMiddleware(loggerMiddleware)
);

8.2 Express中間件(Node.js中的攔截)

// 請求日志中間件
function requestLogger(req, res, next) {
  const start = Date.now();
  
  res.on('finish', () => {
    const duration = Date.now() - start;
    console.log(`${req.method} ${req.originalUrl} - ${res.statusCode} (${duration}ms)`);
  });
  
  next();
}

// 錯誤處理中間件
function errorHandler(err, req, res, next) {
  console.error('發(fā)生錯誤:', err.stack);
  res.status(500).send('服務(wù)器錯誤');
}

// 使用中間件
app.use(requestLogger);
app.use(errorHandler);

通過以上技術(shù)方案,您可以在JavaScript中實現(xiàn)各種級別的函數(shù)執(zhí)行攔截,滿足不同場景下的需求。從簡單的日志記錄到復(fù)雜的AOP編程,選擇適合您項目需求的攔截策略,并注意平衡功能與性能的關(guān)系。

以上就是JavaScript實現(xiàn)函數(shù)執(zhí)行攔截的多種方法的詳細(xì)內(nèi)容,更多關(guān)于JavaScript函數(shù)執(zhí)行攔截的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

最新評論

顺平县| 托克逊县| 贵阳市| 赤峰市| 霍林郭勒市| 肇州县| 安义县| 康乐县| 吉水县| 科技| 广昌县| 温泉县| 高碑店市| 江口县| 丰宁| 海伦市| 大化| 宁武县| 铜梁县| 佛冈县| 和田县| 工布江达县| 吴川市| 万载县| 江源县| 阿拉善左旗| 宁陵县| 阜新市| 普安县| 内乡县| 米脂县| 彰化市| 天台县| 偏关县| 聂荣县| 三明市| 潮州市| 陕西省| 大荔县| 宜兰县| 峨边|