javascript-patterns

cat.gif

更新記錄

item note
20160815 第一版

目錄


Chapter2

永遠使用var來宣告變數

  • 建議方式

    1
    2
    3
    4
    5
    function sum(x,y){
    //定義result為區域變數
    var result = x + y;
    return result;
    }
  • 不建議方式

    1
    2
    3
    4
    5
    function sum(x,y){
    //有可能使用到全域變數result
    result = x + y;
    return result;
    }

變數var

  • 用var定義全域變不可以刪除
  • 不使用var定義全域變數(即不小心在函數中產生)可以刪除

  • 範例

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    $ cat test-var.js 
    var g_var = 1;
    g_novar = 2;

    (function (){
    g_fromfunc = 3;
    }());

    console.log(delete g_var);
    console.log(delete g_novar);
    console.log(delete g_fromfunc);

    console.log(typeof g_var);
    console.log(typeof g_novar);
    console.log(typeof g_fromfunc);
  • 測試

    1
    2
    3
    4
    5
    6
    false
    true
    true
    number
    undefined
    undefined

用單個var定義多個變數

  • 用單個var定義多個變數
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10

    function func(){
    var a = 1,
    b = 2,
    sum = a + b,
    myobject = {},
    i,
    j;
    //
    }

物件實字語法

  • 將物件用 { } 包起來
  • 用逗號(,)分開物件內每個屬性及函數
    1
    2
    3
    4
    5
    6
    var dog = {
    name: "Benji"
    getName: function () {
    return this.name;
    }
    };

避免隱含的型別轉換

  • JavaScript在比較時會隱含的做型別轉換
    false == 0 或 “” == 0 會回傳true

  • 使用確定的比較 === , !==

    1
    2
    3
    4
     var zero = 0;
    if ( zero === false ){
    // 不會執行,因為zero是0非false
    }
  • 避免隱含的型別轉換比較,除非你知道你在做什麼

    1
    2
    3
    4
    var zero = 0;
    if ( zero == false ){
    // 會執行
    }

分號插入機制(semicolon insertion mechanism)

  • JavaScrpt允語你在行尾遺漏分號,還會自動幫你加一個
    要養成左括號 { 的位置要寫在同行,避免隱含的分號
    永遠應該加上分號,即便JavaScript解析器會隱含的補上

  • 正確的寫法方式

    1
    2
    3
    4
    5
    function func() {
    return {
    name: "Batman"
    };
    }
  • 錯誤的寫法方式 : 非預期的回傳值

    1
    2
    3
    4
    5
    6
    function func() {
    return
    {
    name: "Batman"
    };
    }
  • 由於隱含的分號,等同於下面的寫法

    1
    2
    3
    4
    5
    6
    function func() {
    return undefined;
    {
    name: "Batman"
    };
    }

寫作習慣:空格

  • for中各部分的分號之後

    1
    2
    3
    for ( var i = 0; i < 10; i += 1){
    ...
    }
  • 區隔array物件的逗號之後

    1
    var a = [1, 2, 3];
  • 區隔屬性名稱和值的分號之後

    1
    var o = {a: 1, b: 2};
  • 函數宣告的左括號之前

    1
    function myFunc() {}
  • 區隔所有的運算元和運算子
    +, -, *, =, <

    1
    2
    3
    4
    5
    6
    7
    var d = 0,
    a = b + 1;

    if ( a && b && c) {
    d = a % c;
    a += d;
    }
  • 左括號 { 之前應該加上空格,ex. 函數、if-else, loop..等

  • 右括號 } 和else, while之間應該加上空格
    1
    2
    3
    4
    5
    if (true) {
    alert(1);
    } else {
    alert(2);
    }

Chapter2 命名慣例

讓建構試為首字母大寫

  • js沒有class,但有使用new引發的建構式函式
    1
    2
    3
    4
    5
    function MyConstructor() {...}
    function Person() {...}
    function myFunction() {...}

    var adam = new Person();

字詞的分隔方式

  • 建構式,採用大駝峰式命名法(upper camel case)
    MyConstructor()

  • 一般的函數名稱採用小駝峰式命名法(lower camerl case)
    myFunction(), calculateArea(), getFirstName()

  • 非函式的變數,採用小駝峰式命名法
    lastIndex, ignoreCase

其他命名模式

  • 用全部大寫字母命名全域變數

    1
    2
    var PI = 3.14,
    MAX_WIDTH = 800;
  • 用底線 _ 當成private成員
    getName()表示為public
    _getFirst(), _getLast()表示為private
    它們雖然仍是普通的public函式,但加上低線便是提醒使用者

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    var person = {
    getName: function () {
    return this._getFirst() + ' ' + this._getLast();
    }
    _getFirst: function() {
    ...
    }
    _getLast: function() {
    ...
    }
    }

Chapter2 Variable Hoisting

了解變數的拉升(Variable Hoisting)

  • 變數player在其中被宣告的最接近的範疇(scop)
  • JavaScript不支援 block scoping
  • 在同一個function內變數,在執行時會被拉升到function的頭
    即定義var player,而在後才由程式設定值
    變數只有var xx ,此時尚未define,當設定值時才會define ex. number , class , function

  • 某些程式設計師偏好,把所有的var宣告放到它們函數的頂端
    等同於手動起把它們的變數拉升,以避免歧義(ambiguity)

  • 錯誤的寫法如下
    此時的player非外部傳內,而是function定義

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    function isWinner(player, others) {
    var highest = 0;
    for (var i = 0, n = other.length; i < n; i++){
    var player = other[i];
    if(player.score > highest){
    highest = player.score;
    }
    }

    return player.score > highest;
    }
  • 變數的拉升
    左邊為程式內容,右邊為實際在跑時直譯的解析方式
    在function內的變數會先在頭定義,之後在設定值(此時才會define變數)
    圖片來源:Effective JavaScript page 45

Variable Hoisting Example

  • 範例

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    $ cat ja-hoisting.js 
    function foo(){
    console.log('global foo');
    }
    function bar(){
    console.log('global bar');
    }

    function hoistMe(){
    console.log(typeof foo);
    console.log(typeof bar);

    foo();
    // bar();

    function foo(){
    console.log('local foo');
    }
    var bar = function(){
    console.log('local bar');
    };
    }
    hoistMe();
  • 測試

    1
    2
    3
    function
    undefined
    local foo

單元測試

同事提供了不錯的測試範例

  • 先想一下,會打印結果
  • 再用node試一下真正的結果跟預期的是否相同

  • Variable Hoisting 測試一

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    var y = 1;

    function f() {
    if(!y){
    var y = 0;
    }
    console.log(y);
    }

    f();
  • Variable Hoisting 測試二

    1
    2
    3
    4
    5
    6
    7
    8
    9
    var y = 1;

    function f(){
    y = 0;
    return;
    function y(){}
    }
    f();
    console.log(y);

Chapter3 物件實体

物件 (Creating objects)

Object initializer

  • 空物件
    An empty object with no properties can be created like this:

    1
    var dog = {};
  • 非空物件

    1
    2
    3
    4
    5
    6
    var dog = {
    name: "Benji" ,
    getName: function () {
    return this.name;
    }
    }
  • Accessing properties

    1
    2
    dog.name;	// "Benji"
    dog["name"]; // "Benji"
  • 物件實体語法
    物件用大括號包起來 { }
    用逗號分隔物件內每個屬性和函式
    用逗號分隔屬性名稱和屬性值

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    var apple = {
    type: "macintosh",
    color: "red",
    getInfo: function () {
    return this.color + ' ' + this.type + ' apple';
    }
    }

    apple.color = "reddish";
    console.log(apple.getInfo());

    $ node class.js
    reddish macintosh apple

用建構式(new ..)建立物件

  • 可以使用自已的建構函式建位物件,
  • 或使用內建的建構式Object()、Date()、String()
  • 標準內建物件

  • 建立物件方式有下例兩個方式

    • <1> 建議採用方式

      1
      var car = {goes: "far"};
    • <2> 不建議採用方式
      Creates a new object by copying the values of all enumerable own properties from one or more source objects to a target object.
      不要使用new Object(),應該使用較簡單而且更可靠的物件實子替代

      1
      2
      var car = new Object();
      car .goes = "far";

    自訂建構式函數

  • $ cat chapter3-person.js

    1
    2
    3
    4
    5
    6
    7
    8
    9
    var Person = function (name) {
    this.name = name;
    this.say = function () {
    return "I am " + this.name;
    };
    }

    var adm = new Person("Adam");
    console.log(adm.say());
  • $node chapter3-person.js

    1
    I am Adam
  • New建構式程序如下

    • 建立空物件,參考至this變數
    • 使用this加入變數及函數
    • 回傳this
    1
    2
    3
    4
    5
    6
    7
    8
    9
     var Person = function (name) {
    // var this = {};
    this.name = name;
    this.say = function () {
    return "I am " + this.name;
    };

    // return this;
    }

如何把function加入物件原型(prototype)中

  • 由於每個new Person都會建立新的say function
    但皆是相同的功同,可以使用prototype功能,讓所有的
    Person都參考同一個功能,減少記憶体
  • 如何把say function加入Persion原型中
  • $ cat chapter3-person2.js
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    var Person = function (name) {
    this.name = name;
    }

    Person.prototype.say = function () {
    return "I am " + this.name;
    }

    var adm = new Person("Adam");
    console.log(adm.say());

Chapter4 函數(待增加)


Chapter5 物件建立模式(待增加)


Chapter6 程式碼重用模式(待增加)


Chapter7 設計模式(待增加)


Chapter8 DOM和劉覽器的模式(待增加)

參考