2015年12月25日 星期五

[JavaScript] JavaScript inheritance patterns

JavaScript 要怎麼做繼承,整理了一些寫法:
  • ES2015 (ES6)
  • Function Pattern
  • 不 return、使用 call (or apply) + new 的方法實作 (all in one)
  • Pseudo-Classical pattern 
環境:Chrome v47.0.2526.106

一些基礎知識 (須看懂這裡,下面才看的懂QQ)


__proto__:用來指向(pointing) prototype 的 property。

prototype:每個 object 都有 prototype,prototype 自己也是 object,Object 會繼承他們的 prototype 的屬性和方法。

Object.prototype是最上層的 prototype chain。

Object.create(prototype):建立一個 new object 並把其 __proto__ 設定成指定 object 的 properties。

Object.setPrototypeOf(obj, proto):設定 obj 的 prototype 為指定的 prototype,原型為 object.__proto__ = prototype。

prototype chain (__proto__ chain 或原型鏈):JavaScript 會先找 Instance 自己有沒有 property,沒有會經由 __proto__ 去找上一層的 prototype,沒有再找上一層,直到 Object.prototype。

下述範例 Car 的 prototype 就包含了 name、driver、getName()、run()。
var Car = function(name) {
    this.name = name || "car";
};
Car.prototype = {
    name    : "",
    driver  : "",
    getName : function() {
        return this.name;
    },
    run     : function () {
        console.log(this.name + " is running");
    },
};
把 Car 印出如下圖,他的上一層是 Function.prototyp,top 是 Object.prorotype


要呼叫 像 getName 需要使用 Car.prototype.getName() 才能呼叫,
直接 Car.getName() 會有錯誤 Uncaught TypeError: Car.getName is not a function。
不過要呼叫 Function.prorotype.call() 就可以直接使用 Car.call() 去呼叫 。
要呼叫 Object.prorotype.isPrototypeOf() 可以直接使用 Car.isPrototypeOf() 去呼叫 。
表示經由 __proto__往上尋找。

function: 把一個變數宣告為 function 時,如下
var Car = function(name) {
    this.name = name;
};
如圖,會繼承 Function.prototype,並且會把 Car 的 prototype.constructor 指向 Car 自己這個 function 。

prototype.constructor:指向 function 本身。本來以為跟 new constructor 會優先找這個並由這裡開始做 constructor 進入點,但實驗在 Chrome 時 new 不會看這個。

new constructor:
用實例來說明
var car = new Car(); 

console.log(car instanceof Car); //true


會先檢查 Car 是不是 function,需要是 function ,因為會拿來做 constructor。
  1. 建立 Object。
  2. 繼承 Car。
  3. 呼叫 Constructor (Car function)。
  4. 需要注意,如果 Constructor (Car function)有 return value 時 car 會被這個 return value 取代掉。
很像下列程式
var car = {};
car.__proto__ = Car.prototype; // 等同 Object.setPrototypeOf(car, Car.prototype);
Car.call(car, "CAR");

console.log(car instanceof Car); // true

或著

var car = Object.create(Car.prototype);
Car.call(car, "CAR");

console.log(car instanceof Car); // true
很接近不等於,差別是用 new 下圖是 Car,但用上列程式結果是 Object。
結果如下圖 (這裡 prototype.constructor 不見,是因為程式是直接設定 prototype 所以洗掉了)
用 new  constructor                          用 Object.create or __proto__ or Object.setPrototypeOf









ES 2015 (ES6)


ES2015 新增和支援 class、extends、constructor、super、set、get、static 等保留字,可以像其他語言寫出一個簡單的 class 並且使用 extend 來繼承母類別。最大的好處是類似 c++、java、php 等直覺寫法。不過目前尚未支援像是 public、protected、private 等 access modifiers,所以無法設定 private method。

如以下範例 (這裡是使用 Babel 來編輯)。
class Car {
    constructor(name){
        this.name = name || "car";
    }
    getName() {
        return this.name;
    }
    run () {
        console.log("car is running");
    }
    set driver(name) {
        this.driver = name;
    }
    get driver() {
        return this.driver;
    }
}
class Formula extends Car {
    constructor(name, color){
        super(name || "F1");
        this.color = color;
    }
    getColor() {
        return this.color;
    }
    run () {
        console.log("F1 is running");
    }
}
實驗結果,符合預期。
var car = new Car("i am a car");
console.log(car.getName());  // CAR
car.run();                   // CAR is running
car.driver = "toolman";
console.log(car.driver);     // toolman
console.log(car.getColor()); // Uncaught TypeError: car.getColor is not a function
console.log(car instanceof Car);     //true
console.log(car instanceof Formula); //false

var f1 = new Formula("i am a F1", "red");
console.log(f1.getName());   // F91
f1.run();                    // red F91 is running
console.log(f1.getColor());  // red
f1.driver = "prettygirl";
console.log(f1.driver);      // prettygirl
console.log(f1 instanceof Car);     //true
console.log(f1 instanceof Formula); //true

Function pattern(或稱 Factory constructor patter)


使用 Closure 的技巧直接在 function return 實做好的 object,子類別也是直接呼叫父類別 function 取得的 object 後,擴增完成,再 return。這個方法好處在於能實作出 private variable(name、color) 和 method (_run) 的效果。但缺點會失去繼承的結構,所以無法使用 instanceof 來判斷 instance 是屬於那個 class 產生的,或是那個 class 的子類別。(使用此 pattern 可以不用 new ,因為有沒有用結果都一樣)。
另外其實也可以自己連接 __proto__ 到父的 prototype 讓其有繼承關係。
var Car = function(setname) {
    var that = {};
    var name = setname || "car";
    that.getName = function() {
        return name;
    };
    var _run = function () {
        return name + " is running";
    };
    that.run = function () {
        console.log(_run());
    };
    that.driver = "";
    return that;
};

var Formula = function(name, color) {
    var that = Car(name);
    that.getColor = function() {
        return color;
    };
    that.run = function() {
        console.log(color + " " + that.getName() +" is running");
    };
    return that;
}
實驗結果 (其他結果跟 ES2015 一樣就不重複了,看 instanceof 的結果)
發現不屬於任何 class
var car = Car("i am a car");
console.log(car instanceof Car);     //false
console.log(car instanceof Formula); //false

var f1 = Formula("i am a F1", "red");
console.log(f1 instanceof Car);     //false
console.log(f1 instanceof Formula); //false
左邊是 car 的 instance                                       右邊是 f1 的 instance

可以由圖看出上一層直接是 Object 了,所以無法用 instanceof 判斷是不是從 Car or Formula 繼承的 instance。

不 return,使用 call (or apply) + new 的方法實作 (or all in one)


這個方法跟上述很接近,利用 call (or apply )+ new(需要用 new constructor 上述有寫 new 的行為) 所以直接使用 this 並且不 return 。也可以實作出有 private 效果的 method、variable,所以關鍵在子類別的 Car.call(this, arg1)把 this extend。優點在於能實作出 private 效果,有記住自己是由那個 class 所產生,無法判斷父類別是誰,所以像 design pattern 常用的 abscract class 就比較不適合。
一樣也可以自己連接 __proto__ 到父的 prototype 讓其有繼承關係。
var Car = function(setname) {
    var name = setname || "car";
    this.getName = function() {
        return name;
    };
    var _run = function () {
        return name + " is running";
    };
    this.run = function () {
        console.log(_run());
    };
    this.driver = "";
};

var Formula = function(name, color) {
    Car.call(this, name || "F1");
    this.getColor = function() {
        return color;
    };
    this.run = function() {
        console.log(color + " " + this.getName() +" is running");
    };
}
實驗結果,記得自己是由那個 class 衍生出來的,但無法判斷父類別是什麼。
var car = new Car("i am a car");
console.log(car instanceof Car);     //true
console.log(car instanceof Formula); //false

var f1 = new Formula("i am a F1", "red");
console.log(f1 instanceof Car);     //false
console.log(f1 instanceof Formula); //true
左邊是 car 的 instance                                                        右邊是 f1 的 instance

 

由圖可以看出
car -> Car -> Object
f1 -> Formula -> Object
的關係,符合 instanceof 測試結果。

Pseudo-Classical pattern


過去最標準的作法,使用 prototype 來設定 variable 和 method 並利用 Object.setPrototypeOf() 或 __proto__ 指向父類別來實現繼承。
使用 prototype 好處是在 new 時 prototyp 是參考型別( __proto__ 指向 prototype),不會重複建立 method 和 variable,較 function pattern 有效率和節省 memory。
這個方法優點是有完整的繼承關係,而且跟前述幾種方法 (除 ES2015,用 babel 模擬,非瀏覽器內建實作) 在 instance 結構上也是最省的。缺點要記得 extend 。

function extends(child, parent) {
    Object.setPrototypeOf(child.prototype, parent.prototype);
    // 等同 child.prototype.__proto__ = parent.prototype;
}

var Car = function(name) {
    this.name = name || "car";
};
Car.prototype = {
    constructor : Car,
    name    : "",
    driver  : "",
    getName : function() {
        return this.name;
    },
    run     : function () {
        console.log(this.name + " is running");
    },
};

var Formula = function(name, color) {
    this.name = name;
    this.color = color;
};
Formula.prototype = {
    constructor : Formula,
    getColor : function() {
        return this.color;
    },
    run      : function() {
        console.log(this.color + " " + this.name +" is running");
    }
};
extends(Formula, Car);
實驗結果
var car = new Car("i am a car");
console.log(car instanceof Car);     //true
console.log(car instanceof Formula); //false

var f1 = new Formula("i am a F1", "red");
console.log(f1 instanceof Car);     //true
console.log(f1 instanceof Formula); //true
左邊是 car 的 instance                                                        右邊是 f1 的 instance

由圖可以看出
car -> Car -> Object
f1 -> Formula -> Car -> Object
的關係,符合 instanceof 測試結果。


再來依據前述的一些觀念,可能會有人問為什麼不把 extend 放在子類別人?如下程式。
這樣好處是好讀比較會記得。但缺點是設定 __proto__是 cost 很大的動作(),放進去後,每次 new 都會重設一次,所以一般還是放在外面居多。不過這點我也是抱著懷疑,因為 javascript 在 set object 時,不是都是 call by sharing? reference to the object
function extend(child, parent) {
    Object.setPrototypeOf(child.__proto__, parent.prototype);
    // 等同 child.__proto__.__proto__ = parent.prototype;
}

var Car = function(name) {
    this.name = name || "car";
};
Car.prototype = {
    constructor : Car,
    name    : "",
    driver  : "",
    getName : function() {
        return this.name;
    },
    run     : function () {
        console.log(this.name + " is running");
    },
};

var Formula = function(name, color) {
    extend(this, Car);
    this.name = name;
    this.color = color;

};
Formula.prototype = {
    constructor : Formula,
    getColor : function() {
        return this.color;
    },
    run      : function() {
        console.log(this.color + " " + this.name +" is running");
    }
};

結論

方法 2,3 都可以用 pseudo classical 的 extend 類似的方法去完成繼承關係。這幾個差別就看實際上的要不要 private 應用、怎麼寫法自己喜歡、或是在不在意使不使用 prototype 的效能上的差異。好壞差異不大。未來當然都是使用 ES2015 最好的。


Reference:


http://www.w3schools.com/js/js_object_prototypes.asp
http://stackoverflow.com/questions/650764/how-does-proto-differ-from-constructor-prototype
http://dmitrysoshnikov.com/ecmascript/javascript-the-core/
http://davidshariff.com/blog/javascript-inheritance-patterns/
https://medium.com/@PitaJ/javascript-inheritance-patterns-179d8f6c143c#.qbayiakzb
http://es6.ruanyifeng.com/#docs/class
http://www.codedata.com.tw/javascript/essential-javascript-14-constructor/
http://www.codedata.com.tw/javascript/essential-javascript-15-prototype/
http://www.codedata.com.tw/javascript/essential-javascript-16-introspection/
http://www.codedata.com.tw/javascript/essential-javascript-18-class-based-oo-simulation/
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/new
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/create
https://developer.mozilla.org/zh-TW/docs/Web/JavaScript/Reference/Global_Objects/Object/setPrototypeOf

2015年12月23日 星期三

[HTML] HTML5 針對外部來源的 script 上的 async 和 defer

ps:async 和 defere 需要 script 有 src 時才會有效


1. 正常的 script 宣告如下

<script src="wait1.js"><script>
在以前習慣把 <script> 都放在 html 結構的最後面
主要原因是 browser 在 html parsing 碰到 script 時會暫停 html parsing ,會先下載 script 和執行 script 後才會繼續往下做 html parsing。

所以想看到一個網頁呈現必須等 script 處理完,才能看到網頁,而大部份實務上的應用, script 的執行幾乎都是在 HTML ready 後,才需要執行。

2. async 

<script src="wait1.js" async><script>
async 在碰到 script 時,會開始下載 script 但不會暫停 HTML parsing ,直到 script 下載完,才會暫停 HTML parsing,把 script 執行完,才會繼續做 HTML parsing。

但如果引用多個外部的 script 都是使用 async 時,async 並不保證順序性,誰先下載完,誰就會先行執行。

3. defer

defer 碰到 script 時不會暫停 html parsing 並同時下載 script 直到 HTML parsing 結束後才執行 script。defer 跟 async 不同的是把 script 執行 delay 到 HTML parsing 結束後才處理。

不過這個在 w3c 的文件中並沒有說明,當有多個 defer 的外部 script 時,他的執行順序會是如何?是否有保證為宣告順序?因為有些 javascript 是有前後相依性的。例如 bootstrap.js 就必須先執行 jquery.js 才能執行 boostratp.js (有檢查有沒有 jquery),

Ref:
http://www.w3.org/TR/html5/scripting-1.html#attr-script-defer
https://html.spec.whatwg.org/multipage/scripting.html#attr-script-defer
http://www.growingwiththeweb.com/2014/02/async-vs-defer-attributes.html (這篇是有說 defer 有保證順序性,但在測試時 chrome 有,但firefox 並非如此)






舉個實例

瀏覽器
Chrome 47.0.2526.106
Firefox 43.0.2
(由於跟瀏覽器版本支援度有關係,所以放上版號)
wait1.js
alert(1);
wait2.js
alert(2);
wait3.js
alert(3);

實驗 1
<script src="wait1.js" ></script>
hello world 
chrome 和 firefox 都是先 alert(1) 才會出現 hello world

實驗 2
<script src="wait1.js" async></script>
hello world
chrome 和 firefox 都是先出現 hello world 才 alert(1)

實驗 3
<script src="wait1.js" defer></script>
hello world
chrome 和 firefox 都是先出現 hello world 才 alert(1)

實驗 4
<script src="wait1.js" async></script>
<script src="wait2.js" async></script>
<script src="wait3.js" async></script>
hello world
chrom 和 firefox 會先出現 hello world 但是 alert 就會有 1>2>3、2>1>3、3>2>1 的情形

實驗 5
<script src="wait1.js" defer></script>
<script src="wait2.js" defer></script>
<script src="wait3.js" defer></script>
hello world
chrom 會先出現 hello world > alert(1)>alert(2)>alert(3) (有保證順序)
firefox 會先出現 hello world 但是 alert 就會有 1>2>3、2>1>3、3>2>1 的情形 (沒有保證順序)

結論

  • 不管有無使用 async 和 defer ,建議還是把 script 放在最後面宣告,並按相依性先後順序宣告,即使沒有支援 async 和 defer 或支援度較差的瀏覽器也能正確執行。
  • async 和 defer 都沒有順序上的保證 (雖然 chrome 有,不過 spec 上沒有),所以適合使用在 js 之間沒有前後相依性的情況。
  • async 特性比較適合使用在 Javascript 純粹增加 module、class、function 的,不關聯其他 javascript 或是 HTML 使用。
  • defer 實務上對使用體驗是最佳的,但主要也是在順序性上並沒有保證(w3c 建立的 spec),所以使用上也要考慮一下。

延伸


剛好 IThome 現代化網站技術分享上老木大師分享到
http://mei.homin.com.tw/Keynote_the_secrets_of_web_design_performance.html#!p=61
原理
https://developer.mozilla.org/en-US/docs/Games/Techniques/Async_scripts

可以自己動手做 async,但效果跟 async 差不多就是了,不過可以讓不支援 async 的瀏覽器使用
(ps. 這只是 prototype 實務上還要多實驗)

asyncjs.js
(function() {
    var loader = document.getElementsByTagName("script")[0];
    var scripts = loader.getAttribute("data-src");
    scripts = scripts.split("&");
    scripts.forEach(function(element, index, array){
        var script = document.createElement("script");
        script.src = element;
        document.head.appendChild(script);
    })
})();
index.html
<script src="asyncjs.js" data-src="wait1.js&wait2.js&wait3.js"></script>
hello world
實驗
<script src="asyncjs.js" data-src="wait1.js&wait2.js&wait3.js"></script>
hello world
結果是  hello world 先,alert 就會有 1>2>3、2>1>3、3>2>1 的情形
<script src="asyncjs.js" data-src="wait1.js&wait2.js&wait3.js"></script>
<script> alert("blocking") </script>
hello world
blocking、1、2、3 這幾個順序就不一定了,最後才出現 hello world


Defer ?
還沒想到怎麼實作



Reference:

http://peter.sh/experiments/asynchronous-and-deferred-javascript-execution-explained/
http://www.w3.org/TR/html5/scripting-1.html#attr-script-defer
https://html.spec.whatwg.org/multipage/scripting.html#attr-script-defer
http://www.growingwiththeweb.com/2014/02/async-vs-defer-attributes.html

2015年12月17日 星期四

[Node.js] Electron 發佈成可執行檔 APP

Electron v0.36.0
https://github.com/atom/electron/blob/master/docs/tutorial/application-distribution.md
官網文件,看不懂 (未來應該會修正)

後來查了一下原來要裝 electron-packager
(Ref:https://www.youtube.com/watch?v=dz5SnmBzBXc (舊版 youtube 教學)

安裝 electron-packager

https://www.npmjs.com/package/electron-packager
# for use in npm scripts 
npm install electron-packager --save-dev
 
# for use from cli 
npm install electron-packager -g

修改 package.json

  "scripts": {
    "start": "electron main.js",
    "build_mac": "electron-packager . MyApp --platform=darwin --arch=x64 --version=0.36.0 --icon=myapp.icns --asar=true --ignore=node_modules/electron-* ",
    "build_win32": "electron-packager . MyApp --platform=win32 --arch=x64 --version=0.36.0 --icon=myapp.ico --asar=true --ignore=node_modules/electron-* ",
    "build_linux": "electron-packager . MyApp --platform=linux --arch=x64 --version=0.36.0 --icon=myapp.png --asar=true --ignore=node_modules/electron-* "
  },
electron-packager . MyApp 把目前目錄打包成 MyApp 這個名字的 app

--platform:平台
有那些 platform 可以看這個連結
https://github.com/atom/electron/releases

--arch:ia32, x64, all

--version:這裡指的是 electron 的版本
版本建議跟開發的 electron 的版本相同,此時我是使用 0.36.0

--icon:app 的 icon

--asar:true or false 把 source 封裝,比較不容易被看到原始碼

--ignore:忽略檔案,不要打包,建議把 electron 都忽略掉,因為打包後裡面就有了,可以減少檔案大小

要注意 node_modules 是要在 npm install 後的狀態下打包,不要清除

發佈

# Windows  x64
npm run build_win32

# MAC OS X 
npm run build_mac

# LINUX
npm run build_linux
執行完會在此目錄下產生一個新資料夾
像 win32 會出現 MarkApp-win32-x64 ,然後裡面有執行檔
另外此版本的 0.36.0 electron win32 還是怪怪的,開幾次就掛了,而且關不掉
建議先用 npm start 來執行





2015年12月16日 星期三

[Node.js] 初學 Node.js 注意這三點,會比較好上手

1. 同步和非同步執行順序抽像想像


node.js 是 single thread 所以不會有並行
所以 sync 部份跑完才會開始跑 async 或是在 even driven 才跑 async 有點像下圖



async 部份是看誰先排進 async query 內誰先優先執行
所以像
var async_function = function(val, callback){
    process.nextTick(function(){
        callback(val);
    });
};

async_function(1, function(val) {
    console.log(val);
    async_function(2, function(val) {
        console.log(val);
        async_function(3, function(val) {
            console.log(val);
        });
    });
});

console.log(100);
會列出
100
1
2
3
所以在同一個 async scope 會保證其順序性 1 > 2 > 3

再看一個範例,在 sync 等地方再加一個不同的 async scope
var async_function = function(val, callback){
    process.nextTick(function(){
        callback(val);
    });
};

async_function(1, function(val) {
    console.log(val);
    async_function(2, function(val) {
        console.log(val);
        async_function(3, function(val) {
            console.log(val);
        });
    });
});

console.log(100);

async_function(4, function(val) {
    console.log(val);
    async_function(5, function(val) {
        console.log(val);
        async_function(6, function(val) {
            console.log(val);
        });
    });
});
會列出
100
1
4
2
5
3
6
一樣在同一個 async scope 會保證其順序性
1 > 2 > 3
4 > 5 > 6
但不同 scope 會形成交叉,因為在 sync 的 scope 時 1>4 是這順序排進 queue
而印 1 後,2 被排進 queue 內,4 被執行
4印出後,5排進 queue 內,2被執行,以此類堆

推薦可以看下面這篇,會更清楚為什麼會這樣,雖然主要在講為什麼 async 會比較快,但圖片說明很棒,淺顯易懂
http://blogger.gtwang.org/2014/02/node-js-is-faster-than-java-for-concurrent-data-processing-operations.html

另外這篇在講 node.js 的 process queue
http://fred-zone.blogspot.tw/2012/03/nodejs.html


2. 區分是 sync 的 function 還是 async 的 function


這點 JSDC 2015 Jonathan 也有提到
http://www.jongleberry.com/async-control-flow/assets/player/KeynoteDHTMLPlayer.html#8

大部份只要有 callback 幾乎都是 async 的 function
除了 array iteration methods 操作,像 forEach、map...等
(Ref:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/prototype#Iteration_methods)

另外很多 function 如果結尾有 sync 就是同步版的 function
像 fs 內就有,例如 fs.open 是 async 的版本 fs.openSync 就是 sync 的版本


3. Control Flow (俗稱 callback hell)


因為 callback 的方式導致閱讀程式變成很難
而且很多整理程式的方法,都不太適用,例如 design pattern

目前常聽到的解決是使用這三個方法來解:aync、promise、async/await

aync:
https://github.com/caolan/async
我個人目前都是用這個
比較常用的像有 waterfall

promise:
這裡指的是 ES6 的 promise
不過我也還沒研究:D
npm 有一些類似的 modules

async/await:
這裡指的是 ES7 的
npm 也有幾個,但都會降低效能
https://github.com/yortus/asyncawait#5-performance
像這個會降 20%左右

不過另一個經驗在大部份的 refactory 書(像易讀程式之美學)都有提到。
儘量把程式 function 化,讓 function 和 method 只做一件事,即使在 callback hell 中,也能讓程式變的比較好讀。




題外話
http://www.jongleberry.com/async-control-flow/assets/player/KeynoteDHTMLPlayer.html#12
有提到儘量使用 thrown new Error("boom") 取代 thrown "boom"
這樣才有 stack trace 能看

Reference:
http://blogger.gtwang.org/2014/02/node-js-is-faster-than-java-for-concurrent-data-processing-operations.html
http://fred-zone.blogspot.tw/2012/03/nodejs.html
http://www.jongleberry.com/async-control-flow/assets/player/KeynoteDHTMLPlayer.html#8
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/prototype#Iteration_methods
https://github.com/caolan/async
https://github.com/yortus/asyncawait#5-performance

[docker] Docker 1.9 版防火牆問題

這是 docker 1.9 的 issue

docker 預設在啟動時會主動修改 iptable 的設定,讓 docker run -p (or --publish) 的 Port 都能直接穿過 host 的防火牆設定,跟外部連通。所以像 ubuntu ufw 的設定對 docker 就完全沒用。參考了一些方法讓 host 的 iptables 方法,都沒用
https://fralef.me/docker-and-iptables.html
https://svenv.nl/unixandlinux/dockerufw
http://docs.docker.com/engine/userguide/networking/default_network/container-communication/

上述文章,都說明原本可以修改
/etc/default/docker
DOCKER_OPTS 最後面加上 --iptables=false 在啟動時就不會自動修改 iptalbe 
DOCKER_OPTS="--dns 8.8.8.8 --dns 8.8.4.4 --iptables=false"

不過怎麼設定都沒有作用
看了一下,原來有開 issue
issue #9889 已經 closeed 等待下次更新吧
DOCKER_OPTS 目前會沒作用

待修好再來試了

目前不想對外連通的方法
就是拿掉 -p 
或是改成 -p 127.0.0.1:2222:22 讓 container 內的 22 port 只能對上本機 host (127.0.0.1) 2222 port 
這樣只有在 host 能 ssh 到 container
外部就不能透過 2222 port  連到 container 的 ssh






[JavaScript] Vue.js 初探一些要注意的地方


此文件有可能因為時間的演進而與現況不合, Vue.js 正在演進中
目前記錄自己在寫時,碰到一些要注意的地方


1. 不支援巢狀 (nested)
這裡指的巢狀是指 Vue instance 內再包含 Vue instance
雖然 Vue 不會報錯,但是行為會怪怪的。
比較好的做法是 children 是使用 Vue.componet 包起來,這點跟 React 比較接近。

2. methods 的 function name 和 data 的 data name 是共用的
例如下列情況,有可能 foo function 呼叫不到,被 foo data 覆蓋了
data: {
    foo:''
}, 
method:{
      foo:function(){}
}

3. 如果 data binding 的資料為 array 需要注意
(Ref:http://cn.vuejs.org/guide/list.html#问题)
  1. 直接用索引操作,像 vm.items[0] = {msg:"hellow"};
    Vue 有對 array 新增 $set() 的method 來操作
    例如:this.items.$set(0, {msg:"hello"});
  2. 直接對 array 長度修改 (0為清空)
    如 vm.items.leangth = 0; 會建議使用 vm.items = []; 方式操作
另外也有對 array 新增 $remove() 的 method
該方法行為如下

var index = this.items.indexOf(item)
if (index !== -1) {
    this.items.splice(index, 1)
}


4. v-html (等同 innerHTML) 預設不會過濾 xss
建議直接用 {{variable}} or v-text (等同 textContent)方式設置


5. Vue.extend() 
帶進的 options 大多都跟 Vue instance 相同 (平常使用的 Vue() )
除了 data 和 el 這兩個 options
例如以下例子,MyComponet1 和 MyComponet2 會共用 data,這應該不是我們平常想做的
var data = { a: 1 }
var MyComponent1 = Vue.extend({
    data: data
})
var MyComponent2 = Vue.extend({
    data: data
})
建議做法如下,這樣 data 內的值在每個 Componet 會獨立
var MyComponent = Vue.extend({
    data: function () {
        return { a: 1 }
    }
})


6. Vue.componet 的 prop
prop 概念基本上跟 React 差不多,在 Vue 預設是單向的
但可以用關鍵字
.sync 強迫雙向,這表示 children componet 如果修改該 prop 的值,parent 也會更新
.once 只綁定一次,之後不管改 parent 或是 children 都不會變化

另外目前還有一點問題,是如果 prop 是 array or object 會變成雙向的


7. 如果想要當成一個完整 Web Componet (Vue.componet),直接由 Parent 像一般 HTML 元件向 children 取值

可以使用 v-ref 來設定 componet 別名
<div id="parent">
  <user-profile v-ref:profile></user-profile>
</div>
在 parent 時,可以如下方式呼叫 children 的 method
this.$refs.profile.method()
實際上如果不用 v-ref,Vue 自動也會在 this.$children 內 Reference 他的子元件
但比較麻煩的是,children 是個 array 不容易直接判斷你要取某個 Componet (需要回圈)

在 children 也有 this.$parent 去呼叫 parent 的 method


8. vue-validator 還在 Alpha 所以會有一些問題
所以目前蠻多要自己實作的,沒有 angular 那麼多已完成,可以用的
我使用 2.0.0-alpha.6 基本功能上上 required valid 的行為都是正常的
不過 Vue.validator 這個因為有 bug 而無法使用
但換到最新版 2.0.0-alpha.8 基本功能上就 valid 就壞了,還沒深入了解
是我寫法錯誤還是 bug ,至少寫法沿用 alpha 6 是會有錯誤發生






2015年12月11日 星期五

[Growth Hack] Growth Hack 學習心得 & 筆記

這是 xdite 開的班 http://www.growthschool.com/courses/intro_to_growth_hack


基礎知識

AARRR Metrics
http://www.meetclub.tw/article/view/id/34939

MVP (Minimal Viable Product):最小可行性產品

https://twitter.com/ValaAfshar/status/628406092339519488

PMF (Product Market Fit):不會賠錢的狀能,建議創業選可以快速 PMF 的主題,由以下兩點來評估
  • 很熟該領域
  • 市場需求量大


Growth Hack

Growth Hack is a marketing technique developed by technology startupswhich use creativity, analytical thinking, and social metrics to sell products and gain exposure 

講師認為 Growth Hack 結論是做好產品
做好產品本身絕對是重要的基礎,但我個人更喜歡解釋為做好 UX,這樣在思考的視野會較為寬闊,而 Growth Hack 所講的內容也並非只有做好產品其他包含:廣告、行銷、客服...等

矽谷主要是在 PMF 使用的方法

重點環遶於三個點
  • 降低疑慮
  • 增強信心
  • Call to action


使用的方法
不管什麼方法,做好做對產品是必要的基礎,沒此一基礎任何方法都無效
  • Measuring
  • Landing Page
  • A/B Testing
  • Onboarding
  • Customer Support
  • Email List
  • Referral
  • Gaminification
  • Multiple call to action


Measuring:使用一些量測的工具,來數據分析和量化指標
其他工具可以參考:http://www.growthschool.com/posts/17-measurement-tools-funnel

Landing Page:簡單講就是要注重門面,使用者看到的第一個頁面,如果是活動就是活動頁,如果是網站就是首頁,任何使用者要進入你的服務的第一頁
一個好的結構

  • 一句話形容自己:這是做什麼的服務
  • 使用此服務的三大好處:為什麼要用?
  • 運作原理:如何操作
  • 使用者見證或媒體:越多大廠越好
  • Call to action:希望使用者做什麼,通常可能是註冊,或是付費買服服
  • 消除疑慮:免費註冊使用、退款保證、個資保護

A/B Testing:用來測試改善是不是真的有效,例如:optimizely

Onboarding:很重要,養客戶,包含了產品的 UI、行銷方式和客戶之間主動互動及回饋,不過行銷比較多
方法有
  • Remove Friction
    簡單的註冊(免費更好)和參與
    歡迎         
  • Deliver Immediate Value
    可以讓客戶立刻參與的體驗,例如,快速找到自己喜歡的歌
    跟客戶取得回饋,例如,使用上有碰到什麼問題?
    提供一些回饋,例如,填問卷送 xxx
  • Reward Desired behavios
    詢問是否幫忙推薦(要挑真的喜歡的人)
    資料分析
    Transition to a nurturing program:沒講到,幫助使用者更好上手

整體就是讓客戶感覺「就甘心」

Customer Support:客服,線上 or 電話和 FAQ,了解客戶問題在那,可以思考如何改善,另外也能消除疑慮

Email List:訂閱通知,不會寄 spam

Referaral
只有客戶真的喜歡,才問他要不要幫忙推薦
朋友推薦吸引力較大

Gaminification
像 Dropbox 增加空間的活動

Multiple Call to Action:連續技
像 Airbnb 會在 FB 邀請人可以省下多少 coco
像 Sublime text 免費 license 的活動,



個人的結論
做好做對的產品是必要的基礎
Growth hack 本身教的方法適合 PMF 之後
持續改善是不二法則
利用一些行銷手段來提升轉化率
使用一些量化工具,確定手段和改善是否有用處



Reference:
http://www.growthschool.com/guides/growth_hack