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

資訊專欄INFORMATION COLUMN

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

NeverSayNever / 2267人閱讀

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

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

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

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

讓代碼邏輯清晰

可讀性良好

沒(méi)有冗余代碼

前端編寫(xiě)過(guò)程中什么時(shí)候需要面向?qū)ο螅?/b>

在我的日常工作中,最不想做的的就是兩點(diǎn):

復(fù)制粘貼代碼

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

因?yàn)檫@兩種方式,會(huì)讓代碼冗余,而且不易維護(hù)。為什么?

因?yàn)橄嗤拇a,具備相同的邏輯,也就是具備相同的業(yè)務(wù)邏輯場(chǎng)景,如果場(chǎng)景一旦改變,你將會(huì)改變兩處代碼。

ok,到這里,我們來(lái)講一個(gè)具體的業(yè)務(wù)場(chǎng)景。

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

至于第三個(gè)為什么這么寫(xiě),可以看一下這篇文章

階段二:壞代碼的味道

上面的三段代碼多帶帶寫(xiě)出來(lái)沒(méi)啥問(wèn)題,看看下面的可能問(wèn)題就出來(lái),這相當(dāng)于實(shí)現(xiàn)了三個(gè)函數(shù),那么需要在顯示在表格中就需要這樣寫(xiě):

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

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

這樣的寫(xiě)法,看起來(lái)沒(méi)啥問(wèn)題,但是可讀性是很差的,主要體現(xiàn)在兩點(diǎn):

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

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

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

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

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

未開(kāi)始

已完成/未完成

已過(guò)期

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

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

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

需要解決的痛點(diǎn):

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

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

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

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

先睹為快,我們看一下,上面的代碼在面向?qū)ο蟮膶?xiě)法,直接使用es6的class

上面業(yè)務(wù)場(chǎng)景的面向?qū)ο蟮膶?xiě)法
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, "未開(kāi)始"],
    [1, "已過(guò)期"]
  ]);

  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);
    }
  }
  ... ...
  // 省略其他的了
}

那么寫(xiě)好了上面的類,我們應(yīng)該在其他地方怎么引用呢?

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

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

return (
  
    {
      userInfo.userStatus
    }
  
);

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

ok,看了上面的類的寫(xiě)法,我們來(lái)看一下面向?qū)ο蟮膶?xiě)法應(yīng)該要怎么寫(xiě):

面向?qū)ο?/b> 面向?qū)ο蟮娜筇匦?/b>

封裝

繼承

多態(tài)

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

在基本的面向?qū)ο笾杏袔讉€(gè)原則SOLID原則,但是這里我不想詳細(xì)寫(xiě)了,想說(shuō)一下,我在封裝對(duì)象的時(shí)候會(huì)注重的幾個(gè)方面

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

類的行為對(duì)擴(kuò)展是開(kāi)放的,但是對(duì)于修改是不開(kāi)放的(開(kāi)放封閉原則),像上面的寫(xiě)法是存在風(fēng)險(xiǎn)的,因?yàn)樯傻膶?duì)象實(shí)例中的屬性可以被隨意的修改,我加了_,就是防止這種行為,但是最好的方式應(yīng)該是使用get/set方法來(lái)對(duì)屬性限制操作;對(duì)于對(duì)象的屬性,一定要明確,因?yàn)閖s中一個(gè)是沒(méi)有類型的限制不要出現(xiàn)下面的寫(xiě)法:

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

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

注意的問(wèn)題

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

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

    status() {
        return this._a;
    }
}

避免下面的行為:

// 方式1:
let { status } = new Base({a: 678});
status() // 會(huì)報(bào)錯(cuò)

而應(yīng)該使用下面的寫(xiě)法:

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

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

最后也是最重要的

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

參考資料

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

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

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

相關(guān)文章

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

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

    hoohack 評(píng)論0 收藏0
  • gitbook: 前端好書(shū)推薦

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

    Ali_ 評(píng)論0 收藏0
  • gitbook: 前端好書(shū)推薦

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

    CocoaChina 評(píng)論0 收藏0
  • gitbook: 前端好書(shū)推薦

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

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

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

    noONE 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<