- The concept of DRY is super simple - do not duplicate codes if there are already in the program. The basic practice is using a function to do a particular action and let other places call the function if they need.
// bad const name1 = 'Bob' const msg1 = 'Hi' console.log(`${name1} says: ${msg1}`) const name2 = 'Tom' const msg2 = `How's it going?` console.log(`${name2} says: ${msg2}`) // good function say(name, message) { console.log(`${name} says: ${message}`) } say('Bob', 'Hi') say('Tom', `How's it going?`) - However, once the requirement changed and we modify the function, of course, all function calls will be affected. That's good we save time.
function say(from, to, message) { console.log(`${from} says ${to}: ${message}`) } say('Bob', 'John', 'Hi') say('Tom', 'Peter', `How's it going?`) - It is very common that we use parameters as inputs to let a function deal with for different situations.
function say(from, to, message) { if (to !== null && to !== undefined) { console.log(`${from} says ${to}: ${message}`) } else { console.log(`${from} says: ${message}`) } } say('Bob', 'John', 'Hi') say('Tom', null, `How's it going?`) - You know, the requirement might change many times because customers are indecisive. Even if they don't, we still have to do refactoring in order to have better code quality. That means we might change codes.
function say(from, to, message, isQuestion) { const ending = isQuestion ? '?' : '.' if (to !== null && to !== undefined) { console.log(`${from} says ${to}: ${message}${ending}`) } else { console.log(`${from} says: ${message}${ending}`) } } say('Bob', null, 'Hi', false) say('Tom', 'Peter', `How's it going`, true) - You will realize that functions have more complex parameters and conditions are very hard to modify. It calls "high coupling" if there are too many places rely on a heavy code.
// the combinations you need to test in order to make sure your function works: say('name', null, 'message', false) say('name', 'name', 'message', false) say('name', null, 'message', true) say('name', 'name', 'message', true) // the combinations you may not expect that will ruin your function: say(null, 'name', 'message', false) say('name', 'name', null, true) - Therefore, when you are trying to DRY your code, be careful that don't put too many codes into one function. The function will be super complex and hard to maintain. It may be a good idea to have small functions instead.
// there are actually 4 scenarios, so it may be a good idea to have 4 functions // new function names are more semantic // there are no magical boolean flag and optional parameters (reduce parameter mistakes) // we get rid of if conditions (reduce the complexity) // once one of the functions changed, we won't affect other functions function talk(name, message) { console.log(`${name} says: ${message}.`) } function askQuestion(name, message) { console.log(`${name} says: ${message}?`) } function talkToSomeone(name, someone, message) { console.log(`${name} says to ${someone}: ${message}.`) } function askQuestionToSomeone(name, someone, message) { console.log(`${name} says to ${someone}: ${message}?`) } talk('Bob', 'Hi') askQuestion('Tom', `How's it going`) talkToSomeone('Bob', 'John', 'Hi') askQuestionToSomeone('Tom', 'Peter', `How's it going`) - This example is overly simple, and the naming actually sucks, but I hope I give you a general idea of how to organize your functions.
2019年7月23日 星期二
Reuse, but don't make a huge function
2017年6月13日 星期二
Javascript 用雙波浪號 ~~ 來 屌炸天 轉型整數前請三思
tl;dr
曾幾何時看到別人 JS 寫雙波浪號 來把 string 轉型成 number 而且是整數
http://qa.helplib.com/84467
例如 ~~'123.456' = 123
其實效果跟 Math.floor('123.456') 一樣
某些瀏覽器可能用雙波浪寫法會快上一些
https://jsperf.com/tilde-vs-floor
然而 Number.MAX_SAFE_INTEGER 是 9007199254740991
照理來說 只要不超過這個數字 應該就沒事吧
事實上 只有 -2147483648 ~ 2147483648 範圍的值有作用
Bitwise operators treat their operands as a sequence of 32 bits (zeroes and ones), rather than as decimal, hexadecimal, or octal numbers. For example, the decimal number nine has a binary representation of 1001. Bitwise operators perform their operations on such binary representations, but they return standard JavaScript numerical values.
The numbers -2147483648 and 2147483647 are the minimum and the maximum integers representable through a 32bit signed number.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Bitwise_Operators
簡單來說只要值超過 2147483648 就 GG 啦
我已經不知多少專案用了這個寫法 祈禱他們都只會小於 2147483648
如果有不幸 我相信接手的人都足夠機智 可以突破盲腸
2014年7月31日 星期四
你所不知道的 JS
- 撰寫 Javascrip 的時候
- 無法宣告型別
- Javascrip 在瀏覽器上運行的時候
- 會檢查型別
- 所有東西都是物件(廣義)
- 物件是存放在記憶體中的資料
- 存在於執行時期
- JavaScript 是由 Object 所組成。Array 是物件、Function 是物件、Objects 是物件。
- 在 JavaScript 的原生資料型態 (Primitive Data Type) 中,只有下列五種類型的「值」(value) 不被視為物件:
- Numbers 數值
- Strings 字串值
- Booleans 布林值
- null 空值
- undefined 未定義值
- 其它的所有東西,都算是物件的一種
- 物件只能靠變數或屬性取用
- 物件是個容器,海納百川 有容乃大
- 物件是個雜湊陣列(HashMap)
- 物件只包含屬性 (Property) 跟方法 (Method or Function)
- 可以直接取得值的稱作屬性,可以執行的稱作方法
- var name = obj.name;
- obj.laughOutLoud();
- 分為原始型別跟物件型別
- 原始型別 number string boolean 有其對應的 原始型別包裹 Number String Boolean
- 不建議直接使用原始型別包裹
- Javascrip 是動態語言 不需編譯就能執行
- 宣告變數用 var
- 有全域變數跟區域變數兩種
- 除非有其非常必要性,否則盡量避免使用全域變數,避免互相影響跟衝突
- 建立變數的時候會同時建立屬性及變數
- 在全域的時候會在根物件建立屬性,這會使得任何地方都能夠過跟物件的該屬性作存取
- 在區域的時候會在內部物件建立屬性,內部物件是個隱形人,你看不到也摸不到他,但是他確實存在
- 區域變數的作用域只以 function 區隔與一般 if for while 大括號範圍無關,故一個 function 內的所有變數都可能會互相影響跟衝突
- 要避免一個 function 內的變數互相影響跟衝突,除了注意命名之外,拆解成數個 function 會是較佳的做法
- 開發時期可以在任何位置使用 var 宣告變數,但是這些變數會在執行時期自動宣告在 function 內的頂端,他只會將變數名稱的宣告置頂(其值為 undefined),賦值的位置仍不變,這種特性稱為 Hoisting,這也是為何 function 內的變數不受大括號範圍影響的原因
- 小道消息指出,大多數人甚至開發 Javascrip 數十年的開發人員,都鮮少有人知道 Hoisting
2013年7月28日 星期日
那些年 我們誤會很深的 Javascript 變數作用域
自從上次學會第一次惹惱隊友就上手 以 JSHint 為例之後
其中有話這麼說:請注意這貨十分殘暴 在惹惱隊友 會先惹惱自己
毫無疑外馬上就中槍
故事是這麼發生的
身為一個 C# 嫻熟的 PG 這段 Foo 是用來表示奇偶數的 很合理吧

正如我剛才所說 身為一個 C# 嫻熟的 PG 把剛剛的 Foo 用 JS 翻寫成這樣 也很合邏輯

說時遲那時快杰哥 JSHint 來了


花了發科 為啥這樣寫是錯的 從古至今一路走來 都這樣寫 難到小弟我錯了嗎?
stackoverflow教教你:http://stackoverflow.com/questions/810313/what-is-the-reason-behind-jslint-saying-there-are-too-many-var-statements
原來 Javascript 是沒有 block scope 的
也就是說 只要在同一個 function 裡面的變數
不管是在 if for while 還是蝦米小 的 block 之中
都能在外部存取變數
也就是說 以這個案例來看 即便離開 for 迴圈 下面仍然抓的到 result 甚至 loop 用的 i 變數
而 Javascript 變數的作用域 唯一的分水嶺 在於這個 var
沒有宣告 var 的變數 會是全域變數 全世界都抓的到他
有宣告 var 的變數 只有在該 function 內可以使用
但是 只要是在 function 內 是無視任何 block 的
所以 JSHint 認為 明明這些變數 並非具有 block scope 約束 但是卻以相似的方式撰寫 是一種誤導行為 所以他不允許
最後 依照 JSHint 拉比法典 的規則 必須寫成這樣 只有 一個 var 且最好在 function 最上面 避免他說 我們在宣告前就使用變數

但是老實說 即使是之前的寫法 程式真的會因此出錯嗎 或者在維護上 會讓人搞不清楚嗎 那也不見得
老話一句 工具幫助我們檢查細節 但是 是否要 100% 服從 我想就看誰是杰哥了

2013年7月24日 星期三
第一次惹惱隊友就上手 以 JSHint 為例
身為一個被全世界誤解最深的程式語言(但是最流行)
自由奔放 脫韁野馬 難以馴服 也是常有的
這樣也可以那樣也可以 有時候很方便 但是有時候是噩夢
尤其是 team work 的時候
即便有訂定 coding style
但是人類豈是能相信的動物
在連自己都無法相信的前提之下 我們需要靠工具來惹惱隊友
燈燈燈~JSHint!!!
只要把 CODE 貼上來他就會「嚴格」的幫你把關
讓你的 CODE 有足夠的資格蓋上 CAS 電宰豬
但是手動一一貼過來檢查未免搞剛
更別說人類不可相信呀!!
燈燈燈~JSLint.VS2012!!!
請注意這貨十分殘暴 在惹惱隊友 會先惹惱自己
工具/擴充功能和更新 可以取得這個整人玩具
琳瑯滿目的調教(?)設定
第二頁 記得選到 JSHint

開始調教(?)前記得把一些 Library 檔案都勾選 Skip on build 否則...很可怕不要問

調教(?)前

華麗的鞭打

調教(?)後

CAS 優良認證
2013年7月21日 星期日
AngularJS 玩弄手札 對 REST 用武器 - $resource
本故事純屬虛構,與一切真實人物、團體、故事無關。
摳頂人都知道 摳頂有許多原則
有時候人在摳頂身不由己 沒原則沒節操 又豈是少有之事
但是君子有所為有所不為 即便再沒原則沒節操 也不能忘記下面這個原則
師父常常跟我這麼說:
要把程式寫的複雜 很簡單 隨便TM怎麼寫 都很複雜 保證你的絕世武功絕不會被偷 包括未來的自己
但是要把程式寫的簡單 很困難 要怎樣寫 才能旁邊這些山頂洞人能一目了然 甚至讓未來的自己讚賞一下前人的偉大
Keep It Simple, Stupid
不怕神一般的需求 只怕豬一般的同事
這便是師父傳授我野球拳的最後一重
從此之後 我便把師父的諄諄教誨謹記在心 只要是 不夠 KISS 的 CODE 都是我的仇敵
而今天要被開刀的 就是這位在虎山被大蟲咬 然後結識又結識 Mr.Q 的朋友
Web API in Web Form 之 SPA 明知山有虎 偏向虎山行 上篇
AngularJS in Web Form 之 SPA 明知山有虎 偏向虎山行 下篇
這位朋友有什麼毛病呢?
他沒什麼毛病 程式能跑也能跳
但是 各位 不夠 KISS 呀
$q 先生這貨很神 果斷牛逼 山頂洞人們十分佩服 信奉其為神 天天三牲蔬果膜拜
那糟糕了 這群山頂洞人 完全不知道在衝三小 那豈不是我要 handle 所有 CRUD
那可不行 對付戰車有穿甲彈 對付這幫山頂洞人 我得找找 對 REST 用武器 好讓我奴役他們 handle 所有 CRUD
今日主角 燈燈燈 ~ 對 REST 用武器 - $resource
老歪文:Mapping an Angular Resource Service to a Web API
首先大斬 roleService.js 56 => 25 行

再來斬 rolesController 115 => 98 行


Web API 跟著改一些

2013年6月16日 星期日
AngularJS 玩弄手札 Mr.Q 非關 Jolin
早在第一次看http://docs.angularjs.org/api/ng.$q的時候就看到 $q 這個望名無法思義的東東了
但是 AngularJS 有 Filter 人類也有 還是自動過濾的 然後因為沒有什麼大麻煩出現 Q 先生就從人類變成被遺忘者
如今就是 Q 先生 重返擂台的時刻!
官網留下一條線索 A promise/deferred implementation inspired by Kris Kowal's Q.
拜請 G 大神之後 發現
緊接著又發現這個
最後是這個
原文:You're Missing the Point of Promises
最後這篇 他的彩蛋是最下面這句:
Q by Kris Kowal and myself: a full-featured promise library with a large, powerful API surface, adapters for Node.js, progress support, and preliminary support for long stack traces.
Q:Kris Kowal和我写的,一个promise特性完全实现的类库,有丰富的API、Node.js的支持、处理流支持,以及初步的对于长堆栈的支持。
如果你是個牛仔 不用麻煩了 是你的口頭禪
那我就大發慈悲的擅自作主幫你做結論
1.Javascript非同步程式設計 基本四式 : 回呼函數、事件監聽、發佈/訂閱、Promises物件
2.有人覺得 J蛞蝓 它的promises在錯誤處理上的實現是完全錯誤的
3.Q 先生 是幾位神人生出來的 一個promise特性完全實現的類庫
故事講完了 回歸現實 AngularJS 的 Q 先生 要怎麼玩呢?
首先看看官網怎麼說...尼瑪 當初就是看不懂 Q 先生 才變成被遺忘者
還是看看神人解釋http://zouyesheng.com/angular.html#toc40
神文章 果斷鞭辟入裡
但是仍舊抽象 做而言不如起而行 立馬來重構一下代碼
要被開刀的就是這位在虎山被大蟲咬的朋友
Web API in Web Form 之 SPA 明知山有虎 偏向虎山行 上篇
AngularJS in Web Form 之 SPA 明知山有虎 偏向虎山行 下篇
這位朋友有什麼毛病呢?
神人說 MVC Model 要肥、Controller 要輕、View 要夠笨 這傢伙的 Controller 顯然比端午節肉粽的肥肉還肥
來吧 跟著 鄭多燕 一起變瘦吧~
html 變這樣 js部分 拆成 app.js、roleService.js 和 rolesController.js

app ... 很空 因為沒有 config ~.~

roleService 注入 $http, $q 專門用來處理呼叫 webAPI

rolesController 注入 $scope, roleService 變笨瘦了 專心處理 $scope


最後...真的有變瘦嗎? 沒有呀 總行數變多了 哈哈
但是 rolesController 本身確實變瘦了
重點在於 roleService 現在可以被任何 Controller 注入使用 不再綁死在 rolesController 之中 也就是達成關注點分離
飯粒檔:http://www.mediafire.com/download/ft9vbfg05ejwhw9/testAPI_%24q.zip
2013年6月12日 星期三
AngularJS 玩弄手札 巢狀 ngRepeat + filter
一般的 filter 範例都長這樣
但是如果來源不是 使用者輸入 而是巢狀 ngRepeat 的某個父元素 要 filter 某個子元素呢