面向切面編程(Aspect-oriented programming,AOP)是一種編程范式。做后端 Java web 的同學,特別是用過 Spring 的同學肯定對它非常熟悉。AOP 是 Spring 框架里面其中一個重要概念??墒窃?Javascript 中,AOP 是一個經常被忽視的技術點。
場景
假設你現在有一個牛逼的日歷彈窗,有一天,老板讓你統計一下每天這個彈窗里面某個按鈕的點擊數,于是你在彈窗里做了埋點;
過了一個星期,老板說用戶反饋這個彈窗好慢,各種卡頓。你想看一下某個函數的平均執行時間,于是你又在彈窗里加上了性能統計代碼。
時間久了,你會發現你的業務邏輯里包含了大量的和業務無關的東西,即使是一些你已經封裝過的函數。
那么 AOP 就是為了解決這類問題而存在的。
關注點分離
分離業務代碼和數據統計代碼(非業務代碼),無論在什么語言中,都是AOP的經典應用之一。從核心關注點中分離出橫切關注點,是 AOP 的核心概念。
在前端的常見需求中,有以下一些業務可以使用 AOP 將其從核心關注點中分離出來
裝飾器(Decorator)
提到 AOP 就要說到裝飾器模式,AOP 經常會和裝飾器模式混為一談。
在ES6之前,要使用裝飾器模式,通常通過Function.prototype.before做前置裝飾,和Function.prototype.after做后置裝飾(見《Javascript設計模式和開發實踐》)。
Javascript 引入的 Decorator ,和 Java 的注解在語法上很類似,不過在語義上沒有一丁點關系。Decorator 提案提供了對 Javascript 的類和類里的方法進行裝飾的能力。(盡管只是在編譯時運行的函數語法糖)
埋點數據上報
因為在使用 React 的實際開發中有大量基于 Class 的 Component,所以我這里用 React 來舉例。
比如現在頁面中有一個button,點擊這個button會彈出一個彈窗,與此同時要進行數據上報,來統計有多少用戶點擊了這個登錄button。
import React, { Component } from 'react';import send from './send';class Dialog extends Component { constructor(props) { super(props); } @send showDialog(content) { // do things } render() { return ( <button onClick={() => this.showDialog('show dialog')}>showDialog</button> ) }}export default Dialog;上面代碼引用了@send裝飾器,他會修改這個 Class 上的原型方法,下面是@send裝飾器的實現
export default function send(target, name, descriptor) { let oldValue = descriptor.value; descriptor.value = function () { console.log(`before calling ${name} with`, arguments); return oldValue.apply(this, arguments); }; return descriptor;}
新聞熱點
疑難解答
圖片精選