国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

如何在前端代碼中,應用面向?qū)ο蟮木幊谭妒剑?

NeverSayNever / 2277人閱讀

摘要:為什么要面向?qū)ο竽阈枰赖拿嫦驅(qū)ο竺嫦驅(qū)ο蟛⒉皇轻槍σ环N特定的語言,而是一種編程范式。后端傳遞過來顯示工人完成狀態(tài)的字段代表未完成,代表已完成。其實這就是如何消除代碼副作用的問題將副作用隔離。

為什么要面向?qū)ο螅?/b> 你需要知道的面向?qū)ο?/b>

面向?qū)ο蟛⒉皇轻槍σ环N特定的語言,而是一種編程范式。但是每種語言在設(shè)計之初,都會強烈地支持某種編程范式,比如面向?qū)ο蟮腏ava,而Javascript并不是強烈地支持面向?qū)ο蟆?/p> 什么時候需要面向?qū)ο螅?/b>

任何一名開發(fā)人員,在編寫具體的代碼的時候,不應該為了套用某種編程范式,而去編寫代碼和改造代碼。任何編寫方式的目的是:

讓代碼邏輯清晰

可讀性良好

沒有冗余代碼

前端編寫過程中什么時候需要面向?qū)ο螅?/b>

在我的日常工作中,最不想做的的就是兩點:

復制粘貼代碼

不同的代碼中具備相同的邏輯或者變量

因為這兩種方式,會讓代碼冗余,而且不易維護。為什么?

因為相同的代碼,具備相同的邏輯,也就是具備相同的業(yè)務邏輯場景,如果場景一旦改變,你將會改變兩處代碼。

ok,到這里,我們來講一個具體的業(yè)務場景。

場景1: 前端需要顯示工人的工作完成狀態(tài),如果已經(jīng)完成了,前端提供一個查看詳情的入口,如果沒有完成,提供工人去完成任務的入口。后端傳遞過來顯示工人完成狀態(tài)的字段:user_done_status:0,代表未完成,1代表已完成。前端需要實現(xiàn)這樣一個表格:
工人名字 完成狀態(tài) 操作
小王 已完成 查看詳情
老王 未完成 去完成
階段一:實現(xiàn)最基本的功能
// status.js
// 1:需要一個狀態(tài)映射表,來實現(xiàn)第二列的功能
export const statusMap = new Map([
  [0, "未完成"],
  [1, "已完成"]
]);
// 2: 需要一個動作映射表,來實現(xiàn)第三列的功能
export const actionMap = new Map([
  [0, "查看詳情"],
  [1, "去完成"]  
]);
// 3: 需要一個狀態(tài)判讀函數(shù),來實現(xiàn)第三列的功能
function isUserDone(status) {
  return +status === 1;
}

const actionMap = new Map([
  [status => isUserDone(status), userCanCheckResult],
  [status => !isUserDone(status), needUserToCompoleteWork]
]);

function handleClick() {
  for (let [done, action] of actionMap) {
    if (done()) {
      actionMap();
      return;
    }
  }
}

至于第三個為什么這么寫,可以看一下這篇文章

階段二:壞代碼的味道

上面的三段代碼多帶帶寫出來沒啥問題,看看下面的可能問題就出來,這相當于實現(xiàn)了三個函數(shù),那么需要在顯示在表格中就需要這樣寫:

import {
  statusMap,
  actionMap,
  getUserAction
} from "./status.js"

.... ....
// 第二列
return (
  
    {
      statusMap.get(status)
    }
  
);
// 第三列
return (
   getUserAction(status)}>
    actionMap.get(status)
  
);

這樣的寫法,看起來沒啥問題,但是可讀性是很差的,主要體現(xiàn)在兩點:

三個函數(shù)都和status相關(guān),但是展現(xiàn)形式上是割裂的

每個函數(shù)都需要傳遞一個status

可能有的人會說,這樣把上面的代碼多帶帶抽離出一個文件,也沒什么問題,狀態(tài)也是比較集中的,嗯,這種說法也沒什么問題,多帶帶提取一個文件,用作處理用的狀態(tài),是一種常見的抽象方法。但是可能會遇到下面集中情況,就會讓你很難受:

后端改了下字段,那么你就需要在階段二中的第二列和第三列中傳入?yún)?shù)的地方修改對應的字段名字(估計想宰了rd吧)

業(yè)務場景變化,工人的任務狀態(tài),添加了其他限制,比如任務的時間限制,任務有未開始、進行中、已過期三種狀態(tài),只有當在任務進行中的時候,才可以展示用戶的狀態(tài),否則就展示未開始或者已過期,總結(jié)起來,需要下面的幾種狀態(tài):

未開始

已完成/未完成

已過期

那么顯然,你就需要修改代碼的邏輯,僅僅依靠一個statusMap就不能行了。當然這里有人說了,那我把map編程一個函數(shù):

const getUserStatus = (status, startTime, endTime) => {
  // ...do something
}

這樣是不是就可以了,嗯,說的也沒什么問題,那你需要去修改之前寫的所有代碼,傳入不同的參數(shù),就算一開始你用的不是map而是函數(shù),那么你的代碼也需要再傳入兩個多余的參數(shù),start_time和end_time。

需要解決的痛點:

展現(xiàn)形式的分離,需要一種集中的狀態(tài)處理

需要傳入多個參數(shù)進行判斷,業(yè)務場景的變化或者字段的變化,都需要多處修改代碼

最開始遇到這來那個問題的時候,我想的是怎么樣能夠把所有的處理集中到一起,自然而然就想到了面向?qū)ο螅瑢?strong>用戶的狀態(tài)作為一個對象,對象具備特定的屬性和對應的操作行為。

Javascript中如何編寫面向?qū)ο蟮拇a?

先睹為快,我們看一下,上面的代碼在面向?qū)ο蟮膶懛ǎ苯邮褂胑s6的class

上面業(yè)務場景的面向?qū)ο蟮膶懛?/b>
import moment from "moment";

class UserStatus {
  constructor(props) {
    const keys = [
      user_done_status,
      start_time,
      end_time
    ] ;
    for (let key of keys) {
      this.[`_${key}] = (props || {})[key];
    }
  }

  static StatusMap = new Map([
    [0, "未完成"],
    [1, "已完成"]
  ]);

  static TimeMap = newMap([
    [0, "未開始"],
    [1, "已過期"]
  ]);

  get userDoneStatus () {
    return this._user_done_status;
  }

  get isInWorkingTime() {
    const now = new Date();
    return moment(now).isBetween(moment(this._start_time), moment(this._end_time));
  }

  get isWorkStart() {
    const now = new Date();
    return moment(now).isAfter(moment(now));
  }

  get userStatus () {
    if (this.isInWorkingTime) {
      return UserStatus.StatusMap.get(this.userDoneStatus);
    } else {
      return UserStatus.TimeMap.get(+this.isWorkStart);
    }
  }
  ... ...
  // 省略其他的了
}

那么寫好了上面的類,我們應該在其他地方怎么引用呢?

// 第一步:直接講后端傳過來的信息,構(gòu)造一個新的對象
const userInfo = new UserStatus(info);

// 第二步:直接調(diào)用對應的方法或者參數(shù)

return (
  
    {
      userInfo.userStatus
    }
  
);

以后無論業(yè)務場景如何改變這部分代碼都不需要重新改寫,只需要改寫對應的類的操作就可以了。
這樣看了比較干凈的是具體的view層代碼,就是簡單的html和對應的數(shù)據(jù),沒有其他操作。其實這就是如何消除代碼副作用的問題:將副作用隔離。當你把所有的副作用隔離之后,代碼看起來干凈許多,你像redux-saga就是將對應的異步操作隔離出來。

ok,看了上面的類的寫法,我們來看一下面向?qū)ο蟮膶懛☉撘趺磳懀?/p> 面向?qū)ο?/b> 面向?qū)ο蟮娜筇匦?/b>

封裝

繼承

多態(tài)

特性 特點 舉例
封裝 封裝就是對具體的屬性和實現(xiàn)細節(jié)進行隱藏,形成統(tǒng)一的的整體對外部提供對應的接口 上面的例子就是很好的解釋
繼承 繼承就是子類可以繼承父類的屬性和行為,也可以重寫父類的行為 比如工人有用戶狀態(tài),老板也有用戶狀態(tài),他們都可以繼承UserStatus這一個基類
多態(tài) 同一個行為在在不同的調(diào)用方式下,具備不同的行為,依賴于抽象和重寫 比如工人和老板都具備一個行為那就是吃飯,工人吃的是饅頭,老板吃的是海鮮,同樣是吃這個行為,產(chǎn)生了不同的表現(xiàn)形式
封裝對象的幾個原則

在基本的面向?qū)ο笾杏袔讉€原則SOLID原則,但是這里我不想詳細寫了,想說一下,我在封裝對象的時候會注重的幾個方面

基類與具體數(shù)據(jù)無關(guān),只封裝了特定的行為和屬性,基類只注重抽象公共的部分

類的行為對擴展是開放的,但是對于修改是不開放的(開放封閉原則),像上面的寫法是存在風險的,因為生成的對象實例中的屬性可以被隨意的修改,我加了_,就是防止這種行為,但是最好的方式應該是使用get/set方法來對屬性限制操作;對于對象的屬性,一定要明確,因為js中一個是沒有類型的限制不要出現(xiàn)下面的寫法:

class Base {
  constructor(props) {
    for (let key of props) {
      this[key] = props[key];
    }
  }
}

一個類只應該依賴于他繼承的類,不能依賴于其他類,這樣能最大限度地減少耦合

注意的問題

注意??在js中一定小小心this的使用,假設(shè)有一個初始類:
初始類:

class Base {
    constructor(props) {
        this._a = props.a;
    }

    status() {
        return this._a;
    }
}

避免下面的行為:

// 方式1:
let { status } = new Base({a: 678});
status() // 會報錯

而應該使用下面的寫法:

//方式2:
let info = new Base({a: 678});
info.status(); //輸出正確

根本原因就是this在作怪,第一種this指向了全局作用域。

最后也是最重要的

上面的面向?qū)ο笾饕鉀Q了前文提到的兩個痛點,但是也不是所有的業(yè)務場景都適合面向?qū)ο?/strong>,當你的代碼出現(xiàn)了一些壞味道(代碼容易、代碼分散不易處理),可以考慮下面向?qū)ο螅吘?strong>適合的才是最好的

參考資料

面向?qū)ο蠓庋b的五個原則)
五個原則比較形象的解釋

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/106953.html

相關(guān)文章

  • JavaScript 函數(shù)式編程(一)

    摘要:函數(shù)式編程的哲學就是假定副作用是造成不正當行為的主要原因。函數(shù)組合面向?qū)ο笸ǔ1槐扔鳛槊~,而函數(shù)式編程是動詞。尾遞歸優(yōu)化函數(shù)式編程語言中因為不可變數(shù)據(jù)結(jié)構(gòu)的原因,沒辦法實現(xiàn)循環(huán)。 零、前言 說到函數(shù)式編程,想必各位或多或少都有所耳聞,然而對于函數(shù)式的內(nèi)涵和本質(zhì)可能又有些說不清楚。 所以本文希望針對工程師,從應用(而非學術(shù))的角度將函數(shù)式編程相關(guān)思想和實踐(以 JavaScript 為...

    hoohack 評論0 收藏0
  • gitbook: 前端好書推薦

    摘要:它大致概述并討論了前端工程的實踐如何學習它,以及在年實踐時使用什么工具。目的是每年發(fā)布一次內(nèi)容更新。前端實踐第一部分廣泛描述了前端工程的實踐。對大多數(shù)人來說,函數(shù)式編程看起來更加自然。 1 Front-End Developer Handbook 2017 地址:https://frontendmasters.com/b... 這是任何人都可以用來了解前端開發(fā)實踐的指南。它大致概述并...

    Ali_ 評論0 收藏0
  • gitbook: 前端好書推薦

    摘要:它大致概述并討論了前端工程的實踐如何學習它,以及在年實踐時使用什么工具。目的是每年發(fā)布一次內(nèi)容更新。前端實踐第一部分廣泛描述了前端工程的實踐。對大多數(shù)人來說,函數(shù)式編程看起來更加自然。 1 Front-End Developer Handbook 2017 地址:https://frontendmasters.com/b... 這是任何人都可以用來了解前端開發(fā)實踐的指南。它大致概述并...

    CocoaChina 評論0 收藏0
  • gitbook: 前端好書推薦

    摘要:它大致概述并討論了前端工程的實踐如何學習它,以及在年實踐時使用什么工具。目的是每年發(fā)布一次內(nèi)容更新。前端實踐第一部分廣泛描述了前端工程的實踐。對大多數(shù)人來說,函數(shù)式編程看起來更加自然。 1 Front-End Developer Handbook 2017 地址:https://frontendmasters.com/b... 這是任何人都可以用來了解前端開發(fā)實踐的指南。它大致概述并...

    Warren 評論0 收藏0
  • 編程范式與函數(shù)式編程

    摘要:聲明式編程一種編程范式,與命令式編程相對立。常見的聲明式編程語言有數(shù)據(jù)庫查詢語言,正則表達式邏輯編程函數(shù)式編程組態(tài)管理系統(tǒng)等。函數(shù)式編程,特別是純函數(shù)式編程,嘗試最小化狀態(tài)帶來的副作用,因此被認為是聲明式的。 編程范式與函數(shù)式編程 一、編程范式的分類 常見的編程范式有:函數(shù)式編程、程序編程、面向?qū)ο缶幊獭⒅噶钍骄幊痰取T诿嫦驅(qū)ο缶幊痰氖澜纾绦蚴且幌盗邢嗷プ饔茫ǚ椒ǎ┑膶ο螅–lass...

    noONE 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<