顯示具有 Javascript 標籤的文章。 顯示所有文章
顯示具有 Javascript 標籤的文章。 顯示所有文章

2019年7月23日 星期二

Reuse, but don't make a huge function

  • 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.

2017年6月13日 星期二

Javascript 用雙波浪號 ~~ 來 屌炸天 轉型整數前請三思

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

開發時期:
  1. 撰寫 Javascrip 的時候
  2. 無法宣告型別
執行時期:
  1. Javascrip 在瀏覽器上運行的時候
  2. 會檢查型別
廣義物件:
  1. 所有東西都是物件(廣義)
  2. 物件是存放在記憶體中的資料
  3. 存在於執行時期
狹義物件:
  1. JavaScript 是由 Object 所組成。Array 是物件、Function 是物件、Objects 是物件。
  2. 在 JavaScript 的原生資料型態 (Primitive Data Type) 中,只有下列五種類型的「值」(value) 不被視為物件:
    1. Numbers 數值
    2. Strings 字串值
    3. Booleans 布林值
    4. null 空值
    5. undefined 未定義值
  3. 其它的所有東西,都算是物件的一種
物件:
  1. 物件只能靠變數或屬性取用
  2. 物件是個容器,海納百川 有容乃大
  3. 物件是個雜湊陣列(HashMap)
  4. 物件只包含屬性 (Property) 跟方法 (Method or Function)
  5. 可以直接取得值的稱作屬性,可以執行的稱作方法
    1. var name = obj.name;
    2. obj.laughOutLoud();
型別:
  1. 分為原始型別跟物件型別
  2. 原始型別 number string boolean 有其對應的 原始型別包裹 Number String Boolean
  3. 不建議直接使用原始型別包裹
變數:
  1. Javascrip 是動態語言 不需編譯就能執行
  2. 宣告變數用 var
  3. 有全域變數跟區域變數兩種
  4. 除非有其非常必要性,否則盡量避免使用全域變數,避免互相影響跟衝突
  5. 建立變數的時候會同時建立屬性及變數
    1. 在全域的時候會在根物件建立屬性,這會使得任何地方都能夠過跟物件的該屬性作存取
    2. 在區域的時候會在內部物件建立屬性,內部物件是個隱形人,你看不到也摸不到他,但是他確實存在
  6. 區域變數的作用域只以 function 區隔與一般 if for while 大括號範圍無關,故一個 function 內的所有變數都可能會互相影響跟衝突
  7. 要避免一個 function 內的變數互相影響跟衝突,除了注意命名之外,拆解成數個 function 會是較佳的做法
  8. 開發時期可以在任何位置使用 var 宣告變數,但是這些變數會在執行時期自動宣告在 function 內的頂端,他只會將變數名稱的宣告置頂(其值為 undefined),賦值的位置仍不變,這種特性稱為 Hoisting,這也是為何 function 內的變數不受大括號範圍影響的原因
  9. 小道消息指出,大多數人甚至開發 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

本故事純屬虛構,與一切真實人物、團體、故事無關。





摳頂人都知道 摳頂有許多原則

有時候人在摳頂身不由己 沒原則沒節操 又豈是少有之事

但是君子有所為有所不為 即便再沒原則沒節操 也不能忘記下面這個原則

KISS原則

師父常常跟我這麼說:

要把程式寫的複雜 很簡單 隨便TM怎麼寫 都很複雜 保證你的絕世武功絕不會被偷 包括未來的自己

但是要把程式寫的簡單 很困難 要怎樣寫 才能旁邊這些山頂洞人能一目了然 甚至讓未來的自己讚賞一下前人的偉大

Keep It Simple, Stupid

不怕神一般的需求 只怕豬一般的同事

這便是師父傳授我野球拳的最後一重





從此之後 我便把師父的諄諄教誨謹記在心 只要是 不夠 KISS 的 CODE 都是我的仇敵

而今天要被開刀的 就是這位在虎山被大蟲咬 然後結識又結識 Mr.Q 的朋友

Web API in Web Form 之 SPA 明知山有虎 偏向虎山行 上篇

AngularJS in Web Form 之 SPA 明知山有虎 偏向虎山行 下篇

AngularJS 玩弄手札 Mr.Q 非關 Jolin

這位朋友有什麼毛病呢?

他沒什麼毛病 程式能跑也能跳

但是 各位 不夠 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 大神之後 發現

JavaScript异步编程的Promise模式

緊接著又發現這個

Javascript异步编程的4种方法

最後是這個

你没有抓住Promises的要点

原文: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 範例都長這樣





    <div ng-app>
        <div ng-controller="GagMangaCtrl">
            search.Name:<input type="text" ng-model="search.name" />
            search.Say:<input type="text" ng-model="search.say" />
            search.$:<input type="text" ng-model="search.$" />
            <table>
                <tr ng-repeat="member in GagManga.members | filter:search">
                    <td>{{member.name}}</td>
                    <td>{{member.say}}</td>
                </tr>
            </table>
        </div>
    </div>

    <script src="Scripts/angular.min.js"></script>
    <script>
        function GagMangaCtrl($scope) {
            $scope.GagManga = {
                members: [
                    { name: '熊吉', say: '我也只不過是被大三角板玩弄於股掌之間的一名犧牲者' },
                    { name: '兔美', say: '比起推理我更喜歡報警' },
                    { name: '聖德太子', say: '閉嘴,我聖德太子的字典裡沒有自作自受這個詞!' },
                    { name: '小野妹子', say: '你這字典也太個人主義了吧' },
                    { name: '悟空:', say: '這就是天竺麼?不給力啊,老濕~ ' },
                    { name: '三藏', say: '你們太大意了,蠢材!!擦!!擦!! ' },
                    { name: '河合曾良', say: '您是巴嘎麼 芭蕉桑' },
                    { name: '松尾芭蕉', say: '不是巴嘎 是芭蕉' }
                ]
            };
        };

    </script>




但是如果來源不是 使用者輸入 而是巢狀 ngRepeat 的某個父元素 要 filter 某個子元素呢





    <div ng-app="app" ng-controller="myCtrl" class="well-small">

        <fieldset ng-repeat="degree in degrees">
            <legend>{{degree.Degree}}</legend>
            <span ng-repeat="toxic in toxics | filter : { Degree: degree.ID }" class="alert span3">
                Name: {{toxic.Name}}<br />
                Scientific: {{toxic.Scientific}}
            </span>
        </fieldset>

    </div>

    <script src="Scripts/angular.min.js"></script>
    <script>
        var app = angular.module('app', []);

        app.controller('myCtrl', function ($scope) {

            $scope.degrees = [
                {
                    ID: 0,
                    Degree: 'Mild',
                    IsDeadly: false
                },
                {
                    ID: 1,
                    Degree: 'Moderate',
                    IsDeadly: false
                },
                {
                    ID: 2,
                    Degree: 'Severe',
                    IsDeadly: true
                }
            ];

            $scope.toxics = [
                {
                    ID: 1,
                    Name: "毒澱粉",
                    Scientific: "順丁烯二酸",
                    Degree: 0
                },
                {
                    ID: 2,
                    Name: "毒奶粉",
                    Scientific: "三聚氰胺",
                    Degree: 1
                },
                {
                    ID: 3,
                    Name: "瘦肉精",
                    Scientific: "乙型交感神經受體致效劑",
                    Degree: 0
                },
                {
                    ID: 3,
                    Name: "塑化劑",
                    Scientific: "鄰苯二甲酸酯",
                    Degree: 1
                },
                {
                    ID: 5,
                    Name: "丁丁汁",
                    Scientific: "甲基環丙烷",
                    Degree: 2
                }
            ];
        });


    </script>