【譯】JavaScript 代碼整潔之道-函數篇

{"type":"doc","content":[{"type":"blockquote","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"本文源於翻譯 ","attrs":{}},{"type":"link","attrs":{"href":"https://dev.to/carlillo/clean-code-applied-to-javascript-part-iii-functions-4235","title":"","type":null},"content":[{"type":"text","text":"Clean Code Applied to JavaScript — Part III. Functions","attrs":{}}]}]}],"attrs":{}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在這篇文章中,我們將介紹書寫整潔代碼的基本技巧和建議,並重點關注於可複用的代碼單元 -- ","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"函數","attrs":{}},{"type":"text","text":"。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"本文中所有示例都是用 JavaScript 來實現,但是這些良好的實踐適用於任何編程語言,包括 “最接近硬件”(","attrs":{}},{"type":"link","attrs":{"href":"https://en.wikipedia.org/wiki/Close_to_Metal","title":"","type":null},"content":[{"type":"text","text":"CTM","attrs":{}}]},{"type":"text","text":") 的編程語言。爲什麼要特別強調這一點呢?曾經和同事討論過,他們在工作中使用 C 或 Go 語言做開發,但是並不喜歡將這些實踐應用於開發中,他們甚至認爲在他們使用的編程語言中 “沒有人” 會這樣做。然後我的回答是,只有行動起來纔能有所改變。儘管如此,我們還是對這些實踐的優缺點做了較長時間的討論。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"接下來,我們開始介紹如何將這些技巧應用在具體的開發實踐中。","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"使用默認參數去代替短路操作或條件賦值","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在大多數編程語言中,函數的參數支持設置默認值。這就意味着我們可以在代碼中避免使用短路操作和條件賦值。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"下面的代碼說明了這個例子。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"javascript"},"content":[{"type":"text","text":"function setName(name) {\n const newName = name || 'Juan Palomo';\n}\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"javascript"},"content":[{"type":"text","text":"function setName(name = 'Juan Palomo') {\n // ...\n}\n","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"函數參數(理想情況下不多於 2 個)","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"這條實踐對於提高代碼的質量至關重要,我們應該減少函數中入參的個數。理想情況下入參個數應該不多於 2 個,但也不要被這個數量所困擾,因爲入參的數量還取決於我們使用的編程語言。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"雖然這條建議非常重要,但是我們常常意識不到它的重要性。當一個函數有很多參數時,可以把這些參數組合在一起構成一個對象。我們需要避免使用多個基礎類型 (如字符串、數字、布爾值等) 作爲函數的入參,而是要使用抽象級別更高的對象作爲入參。這樣我們會更接近業務邏輯,並且更加遠離底層實現。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"第一個例子中,我們實現了一個生產漢堡的函數,它有 4 個參數。這些參數是固定的,並且必須按照這個順序傳參,這會給我們帶來很多的限制。這樣的函數在使用的時候不是很靈活。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"第二個例子中,最大的改進就是使用一個對象來作爲參數,只需要傳入一個 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"burger","attrs":{}}],"attrs":{}},{"type":"text","text":" 對象就可以生產出一個 “新漢堡”。通過這種方式,我們將漢堡的基本屬性整合到 1 個對象裏面。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在第三個例子中,我們對傳入的對象進行解構賦值,讓對象的屬性在函數體中可訪問到,但是實際上我們傳入的僅僅是一個參數,這使得這個函數有了更大的靈活性。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"javascript"},"content":[{"type":"text","text":"function newBurger(name, price, ingredients, vegan) {\n // ...\n}\n\nfunction newBurger(burger) {\n // ...\n} \n\nfunction newBurger({ name, price, ingredients, vegan }) {\n // ...\n} \n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"javascript"},"content":[{"type":"text","text":"const burger = {\n name: 'Chicken',\n price: 1.25,\n ingredients: ['chicken'],\n vegan: false,\n};\nnewBurger(burger);\n","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"避免副作用 - 全局變量","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"副作用是未來麻煩的根源。雖然從定義上來說副作用不一定是有害的,但是如果在項目中沒有節制的引起副作用,代碼出錯的可能性就會大大提高。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"因此,本小節的建議是,不惜一切代價避免副作用,並且確保函數是可以被測試到的。下面的示例是一個經典的副作用場景,該函數修改了其作用域之外的變量。導致這個函數根本不能被測試,因爲它沒有要被測試的參數,造成這種情況的本質原因就是這個變量根本不受這個函數管控。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"避免這種副作用的最簡單方法是將此函數作用範圍內的變量都作爲參數進行傳遞。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"javascript"},"content":[{"type":"text","text":"let fruits = 'Banana Apple';\n\nfunction splitFruits() {\n fruits = fruits.split(' ');\n}\n\nsplitFruits();\n\nconsole.log(fruits); // ['Banana', 'Apple'];\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"javascript"},"content":[{"type":"text","text":"function splitFruits(fruits) {\n return fruits.split(' ');\n}\n\nconst fruits = 'Banana Apple';\nconst newFruits = splitFruits(fruits);\n\nconsole.log(fruits); // 'Banana Apple';\nconsole.log(newFruits); // ['Banana', 'Apple'];\n","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"避免副作用 - 可變對象","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"另一個非常重要的副作用就是直接修改對象本身,如果你一直從事計算機相關的工作,你會知道 JavaScript 自誕生以來就是支持對象可變的,目前許多庫都在儘量避免使用可變對象。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在 JavaScript 中,數組的方法一般被分爲兩部分: 一部分是會對數組本身進行修改的方法,例如: push、pop、sort,另一部分是不會對數組本身產生修改的方法例如:filter、reduce 、map 等。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"如果您希望開發團隊能夠寫出整潔、可維護的代碼,您就必須制定特定代碼規範來提高團隊所有成員對代碼和業務邏輯的理解。即使做這件事情可能會使我們的開發效率降低,但是這件事絕對是有意義的。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在這裏給出兩個例子,第一個是改變數組本身,第二個是返回一個新的數組。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"javascript"},"content":[{"type":"text","text":"const addItemToCart = (cart, item) => {\n cart.push({ item, date: Date.now() });\n}; \n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"javascript"},"content":[{"type":"text","text":"const addItemToCart = (cart, item) => {\n return [...cart, {\n item, \n date: Date.now(),\n }];\n};\n","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"函數應該只做一件事","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"這是所有計算機專業都會接觸的編程原則之一,但在實踐中,由於缺乏將理論付諸實踐的能力,導致這些原則沒有得到落實。每個函數只能專注於執行一個任務。當然在開發過程中肯定會有一些比較龐大的功能,它往往由很多的小任務構成,但是我們不應該把這些小的功能放在一個函數中編寫,那樣會造成代碼的耦合。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"因此,函數應該只做一件事。看下面這個例子,這個函數做的事情就是從客戶列表中篩選出活躍的用戶並給他們發送電子郵件。從概念上講,這是一個簡單的業務規則,但在實現它時,它們是兩個明顯獨立的任務。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"javascript"},"content":[{"type":"text","text":"function emailCustomers(customers) {\n customers.forEach((customer) => {\n const customerRecord = database.find(customer);\n if (customerRecord.isActive()) {\n email(client);\n }\n });\n}\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"首先,我們必須過濾出活躍用戶,這步操作就應該被封裝成一個獨立的函數。這裏有一個地方要注意,當您在代碼中準備寫入 “if” 時,您應該考慮是否使用的恰當,雖然這並不意味着是錯誤的寫法,但是在項目中濫用 “if” 肯定是不妥的行爲。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"當我們過濾完成得到了我們需要的用戶之後,我們就需要另一個函數來向每個客戶發送電子郵件。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"javascript"},"content":[{"type":"text","text":"function emailActiveCustomers(customers) {\n customers\n .filter(isActiveCustomer)\n .forEach(email);\n }\n\nfunction isActiveCustomer(customer) {\n const customerRecord = database.find(customer);\n return customerRecord.isActive();\n}\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"請記住,您應該專注於每個函數只做一件事。","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"函數應該只是有一個抽象級別","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"設計函數時必須滿足的另一個要求是,每個函數應僅具有單個抽象級別。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"下面的示例顯示的是一個工具函數。在這個函數中,包含了不同層次的抽象。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"javascript"},"content":[{"type":"text","text":"function parseBetterJSAlternative(code) {\n const REGEXES = [\n // ...\n ];\n\n const statements = code.split(' ');\n const tokens = [];\n REGEXES.forEach((REGEX) => {\n statements.forEach((statement) => {\n // ...\n });\n });\n\n const ast = [];\n tokens.forEach((token) => {\n // lex...\n });\n\n ast.forEach((node) => {\n // parse...\n });\n} \n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"解決這個問題的方法非常簡單,我們只需確定不同的抽象級別,並創建滿足本文所述需求的函數。重構之後的函數如下:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"javascript"},"content":[{"type":"text","text":"const REGEXES = [ // ...];\nfunction tokenize(code) { \n const statements = code.split(' ');\n const tokens = [];\n REGEXES.forEach((REGEX) => {\n statements.forEach((statement) => {\n tokens.push( /* ... */ );\n });\n });\n return tokens;\n}\nfunction lexer(tokens) {\n const ast = [];\n tokens.forEach((token) => ast.push( /* */ ));\n return ast;\n}\nfunction parseBetterJSAlternative(code) {\n const tokens = tokenize(code);\n const ast = lexer(tokens);\n ast.forEach((node) => // parse...);\n}\n","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"優先考慮函數式編程而不是命令式編程","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"本文並不想引起編程範式間的爭論,因爲這不是寫這篇文章的初衷。但是,還是還是希望大家學習函數式編程,並在命令式編程的中使用它。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我推薦閱讀 ","attrs":{}},{"type":"link","attrs":{"href":"https://alvinalexander.com/scala/fp-book/benefits-of-functional-programming","title":"","type":null},"content":[{"type":"text","text":"Alvin Alexander 的博客","attrs":{}}]},{"type":"text","text":",在文章裏介紹了函數式編程的一些好處。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"下面,我總結了在命令中使用函數式編程的主要優點。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"numberedlist","attrs":{"start":1,"normalizeStart":1},"content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":1,"align":null,"origin":null},"content":[{"type":"text","text":"純函數更容易推理","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":2,"align":null,"origin":null},"content":[{"type":"text","text":"測試更容易,而且純函數非常適合基於屬性的測試","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":3,"align":null,"origin":null},"content":[{"type":"text","text":"調試更容易","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":4,"align":null,"origin":null},"content":[{"type":"text","text":"程序更加健壯","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":5,"align":null,"origin":null},"content":[{"type":"text","text":"程序是在更高的層次上編寫的,因此更容易理解","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":6,"align":null,"origin":null},"content":[{"type":"text","text":"函數簽名更有意義","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":7,"align":null,"origin":null},"content":[{"type":"text","text":"並行/併發編程更容易","attrs":{}}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"函數式編程相對於命令式編程相比的另一個特點是代碼更具可讀性。如果你閱讀了這一系列文章的第一篇,你會發現所有高質量代碼都會有一個統一特徵,那就是可讀性強","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"函數式編程在這方面就具有很大的優勢;但對於那些使用命令式編程學習並開始解決問題的初級程序員來說,他們很難使用這種編程範式,因爲它改變了他們的工作習慣。但是在這個行業中,我們必須適應變化,況且目前使用函數式編程的場景越來越多。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"閱讀這段統計商品總價格的代碼,您肯定需要記住這幾個變量: total,i,items,items.length,price; 而在下面的函數式編程實現中,我們只需要三個變量 total,price 和 items。如果您習慣於使用功能性操作符,那麼它的讀取速度非常快,而且非常友好。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"javascript"},"content":[{"type":"text","text":"const items = [{\n name: 'Coffe',\n price: 500\n }, {\n name: 'Ham',\n price: 1500\n }, {\n name: 'Bread',\n price: 150\n }, {\n name: 'Donuts',\n price: 1000\n }\n];\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"javascript"},"content":[{"type":"text","text":"let total = 0;\nfor (let i = 0; i < items.length; i++) {\n total += items[i].price;\n}\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"javascript"},"content":[{"type":"text","text":"const total = items\n .map(({ price }) => price)\n .reduce((total, price) => total + price);\n","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"函數鏈式調用","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我們設計用於操作對象或數據流(在本例中是對象)的函數,通常是執行單個任務的函數。在複雜的場景下,會把這些方法組合起來使用,並且不能引起副作用。這時使用函數的鏈式調用方式會使代碼的可讀性更好。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"如果你瞭解 Linux,你會發現它的每一個命令都旨在做一件事情並且都很好地完成工作,但是操作系統往往都很複雜,這是通過使用管道來組合不同的簡單命令來實現的。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在具體案例中,我們也必須使用類似的做法,無論是使用對象還是函數中。下面將分別展示使用傳統方法和鏈式方法的 Car 。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"javascript"},"content":[{"type":"text","text":"class Car {\n constructor({ make, model, color } = car) {\n /* */\n }\n setMake(make) {\n this.make = make;\n }\n setModel(model) {\n this.model = model;\n }\n setColor(color) {\n this.color = color;\n }\n save() {\n console.log(this.make, this.model, this.color);\n }\n} \nconst car = new Car('WV','Jetta','gray');\ncar.setColor('red');\ncar.save();\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"javascript"},"content":[{"type":"text","text":"class Car {\n constructor({ make, model, color } = car){}\n setMake(make) {\n this.make = make;\n return this;\n }\n setModel(model) {\n this.model = model;\n return this;\n }\n setColor(color) {\n this.color = color;\n return this;\n }\n save() {\n console.log(this.make, this.model, this.color);\n return this;\n }\n}\nconst car = new Car('WV','Jetta','gray')\n.setColor('red')\n.save();\n","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"結論","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在這篇文章中,我們討論了開發人員如何將整潔的代碼應用於各種編程語言中的基礎單元:函數。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"實際上,使用整潔的代碼去編寫函數是十分重要的,因爲函數本身就是爲了解耦代碼而存在的。但是可能因爲我們開發過程中的一些不良習慣導致函數代碼中仍然有很多耦合存在,此外,糟糕的函數設計會導致一些難以發現的嚴重錯誤。隨着我們項目的抽象層次的提高,定位錯誤就會變得更加困難。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"因此,這篇文章中的建議會讓你的代碼質量提升一個級別,但是在沒有充分思考的情況下不要應用它們。請記住,這裏沒有魔法提示或銀彈,但有一套技術可以讓你解決更廣泛的問題。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"最後,我們討論的要點如下:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"使用默認參數而不是短路操作或條件賦值","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"函數參數(最好不多於 2 個)","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"避免副作用 - 全局變量","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"避免副作用 - 可變對象","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"函數應該做一件事","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"函數應該只有一個抽象級別","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"優先考慮函數式編程而不是命令式編程","attrs":{}}]}]}],"attrs":{}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"horizontalrule","attrs":{}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"關注公衆號 “","attrs":{}},{"type":"link","attrs":{"href":"https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/f37bc98a8bae45269ca7982cbb0d344a~tplv-k3u1fbpfcp-zoom-1.image","title":"","type":null},"content":[{"type":"text","text":"KooFE前端團隊","attrs":{}}]},{"type":"text","text":"” 回覆 「JavaScript整潔代碼」有機會獲得 ","attrs":{}},{"type":"link","attrs":{"href":"https://book.douban.com/subject/4199741/","title":"","type":null},"content":[{"type":"text","text":"代碼整潔之道","attrs":{}}]},{"type":"text","text":" 圖書一本。","attrs":{}}]}]}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章