星期四, 4月 13, 2017

[JavaScript] Strict Mode

[JavaScript] Strict Mode


ECMAScript 5的Strict Mode不是ECMAScript 的子集。
Strict Mode 執行上跟Non-Strict Mode下有明顯差異。
Strict Mode 跟Non-Strict Mode可並存。

Strict Mode 將JavaScript再執行一些陷阱語法直接丟明顯的錯誤。
Strict Mode 修正JavaScript Engine難以優化的錯誤。
Strict Mode 禁止了一些未來ECMAScript可能會使用的關鍵字。


開啟Strict Mode

"use strict";

  1. 放在語法前。
  2. 不要將”use strict”用在{}使用,他會失去效果。

{
"use strict";
}

  1. 可以在function scope開啟strict mode。
!function strict() {
  "use strict";
  function nested() {return "So am I!";}
  return "I am strict mode "+ nested();
}();
!function nonStrict() {return "I am non Strict";}();

Strict Mode執行上的不同

  1. 拼寫錯誤的變數(或沒有宣告就存取的變數)會拋出異常。
"use strict";
var nAme;
nEme = 17; // ReferenceError

  1. Silently Fail (程式碼執行不報錯也沒有效果的錯誤)會拋出異常。
"use strict";
var obj1 = {};
Object.defineProperty(obj1, "x", {value: 42, writeable: false}});
obj1.x = 9; //TypeError

var obj2 = {get x(){return 17;}};
obj2.x = 5; // TypeError

var fixed = {};
Object.preventExtensions(fixed);
fixed.newProp = "ohai"; // TypeError

  1. 試圖刪除不可刪除之屬性會拋出異常
"use strict";
delete Object.prototype; // TypeError


  1. Gecko 34以前下方指令會丟出錯誤(ECMAScript6不存在)
"use strict";
var o = {p:1, p:2};

  1. 函數的參數要唯一
function sum(a, a, c) {
  "use strict";
  return a+b+c;
}

  1. 禁止八進位語法
var a = 0o10;
parseInt(a);

"use strict";
var sum = 015 + // SyntaxError
          197 +
          142;

  1. 禁止設置primitive值屬性
!function() {
"use strict";

false.true = "";              //TypeError
(14).sailing = "home";        //TypeError
"with".you = "far away";      //TypeError

}();


簡化變數(variable)的使用


  1. 禁止使用with
"use strict";
var x = 17;
with (obj) // SyntaxError
{
  x; // x mean obj.x or var x? it will make engine can not process optimization. 
}


  1. Strict Mode下的eval不在讓surrounding scope(包圍eval的scope),注入新變數。例如eval(‘var’)

function a () {
  eval('var x=10');
  console.log(x); //x will be create.
}


var x = 17;
var evalX = eval("'use strict'; var x = 42; x"); //this x !== var x=17
console.assert(x === 17);
console.assert(evalX === 42);

2.1 如果eval在Strict Mode下面執行,其代碼會被當作在Strict Mode下為執行。
function strict1(str) {
  'use strict';
  return eval(str); // str will be treated as strict mode code
}
function strict2(f, str) {
  'use strict';
  return f(str); // not eval(...): str is strict if and only
                 // if it invokes strict mode
}
function nonstrict(str) {
  return eval(str); // str is strict if and only 
                    // if it invokes strict mode
}

strict1("'Strict mode code!'");
strict1("'use strict'; 'Strict mode code!'");
strict2(eval, "'Non-strict code.'");
strict2(eval, "'use strict'; 'Strict mode code!'");
nonstrict("'Non-strict code.'");
nonstrict("'use strict'; 'Strict mode code!'");

  1. Strict Mode禁止刪除變數
'use strict';
var a={x:10};
delete a.x; // It can delete

var x;
delete x; // SyntaxError

eval('var y; delete y;'); // SyntaxError



簡化eval跟arguments

  1. 對eval跟arguments誤用的範例如下
"use strict";
eval = 17;
arguments++;
++eval;
var obj = { set p(arguments) { } };
var eval;
try { } catch (arguments) { }
function x(eval) { }
function arguments() { }
var y = function eval() { };
var f = new Function("arguments", "'use strict'; return 17;");

  1. Strict Mode 函數arguments的值,不會隨著參數變數被修改而跟著改變。
function f(a){
  "use strict";
  a = 42; //a 改變,但是函數的arguments仍是f(17);
  return [a, arguments[0]];
}
var pair = f(17);
console.assert(pair[0] === 42);
console.assert(pair[1] === 17);

  1. 不再支援arguments.callee (為了最佳化)
"use strict";
var f = function() { return arguments.callee; };
f(); // TypeError


安全的 JavaScript


  1. Strict Mode下回傳this將不再將整個this包裝(boxed)返回出去,而是undefined, 或是call, apply, bind的this。一般模式下會將this回傳出去,可能會包含許多額外資訊(ex window 物件),同時也有助效能提升。
  • 這也意味瀏覽器將不能透過Strict Mode下的function 回傳this來取得window物件捕捉額外資訊。
'use strict';
function fun() { return this; }
console.assert(fun() === undefined);
console.assert(fun.call(2) === 2);
console.assert(fun.apply(null) === null);
console.assert(fun.call(undefined) === undefined);
console.assert(fun.bind(true)() === true);

  1. Strict Mode下的arguments不再提供”walk” to JavaScript Stack的下面兩個方式 function.caller(誰呼叫我)跟function.arguments(呼叫我的函式的參數),因為這會導致不安全的存取。
function restricted()
{
  "use strict";
  restricted.caller;    // TypeError
  restricted.arguments; // TypeError
}
function privilegedInvoker()
{
  return restricted();
}
privilegedInvoker();

  1. Strict Mode下的arguments不再提供這個函數相關變數的存取方式,例如arguments.caller。這個在現在許多瀏覽器都已經不再存取的到。
 'use strict';
function fun(a, b) {
  'use strict';
  var v = 12;
  return arguments.caller; // throws a TypeError
}
fun(1, 2); // doesn't expose v (or a or b)

保留ECMAScript未來擴充的關鍵字

  1. 關鍵字範例如下
implements, interface, let, package, private, protected, public, static, yield

function package(protected){ // !!!
  "use strict";
  var implements; // !!!

  interface: // !!!
  while (true)
  {
    break interface; // !!!
  }

  function private() { } // !!!
}
function fun(static) { 'use strict'; } // !!!

  1. Strict Mode也禁止了Function Declaration 一些的宣告方式,這也是未來ECMAScript會制訂函式宣告式未來的一些規範。
 'use strict';
if (true)
  function f() { } // SyntaxError
  
for (var i = 0; i < 5; i++) 
  function f2() { } // SyntaxError


function baz() { // ok
  function eit() { } // ok
}


Reference: MDN Strict Mode 嚴格模式

星期四, 2月 09, 2017

Angular $rootScope and $scope Event System

Angular官方對的 $rootScope 的定義如下
Every application has a single root scope. All other scopes are descendant scopes of the root scope. Scopes provide separation between the model and the view, via a mechanism for watching the model for changes. They also provide event emission/broadcast and subscription facility.
 一個ng-app只會有一個 $rootScope,所有的 $scope 都是 $rootScope 的child scope。文件特別把angular的emission/broadcast機制放在定義,這也代表事件處理是 $rootScope 很重要的操作。

$scope.$emit up, $scope.$broadcast down


// firing an event upwards
$scope.$emit('myCustomEvent', 'Data to send');

// firing an event downwards
$scope.$broadcast('myCustomEvent', {
  someProp: 'Sending you an Object!' // send whatever you want
});

// listen for the event in the relevant $scope
$scope.$on('myCustomEvent', function (event, data) {
  console.log(data); // 'Data to send'
});


簡單說明這三個行為

  • $emit 往上(parent)觸發事件
  • $broadcast 往下(child)觸發事件
  • $on 當收到事件所執行的行為


但是$scope的互動並非都是parent-child關係,有可能是Sibling之間要觸發。這時候就會要先$emit parentScope在$broadcast,並不是很方便的寫法。


$scope.$parent.$broadcast('myevent', 'Some data');


$rootScope.($emit/$broadcast)


上面的這種sibling的事件觸發,則可以使用$rootScope代為處理,如下方案例。
簡單說明 $rootScope 的 $emit 跟 $broadcast 的差別。
  • $rootScope.$emit 因為$rootScope沒有父層,所以直接觸發 $rootScope 註冊的事件。
  • $rootScope.$broadcast 往下廣播事件。

<div ng-controller="ParentCtrl as parent" class="ng-scope">
  // ParentCtrl
  <div ng-controller="SiblingOneCtrl as sib1" class="ng-scope">
    // SiblingOneCtrl
  </div>
  <div ng-controller="SiblingTwoCtrl as sib2" class="ng-scope">
    // SiblingTwoCtrl
    <div ng-controller="ChildCtrl as child" class="ng-scope">
      // ChildCtrl
    </div>
  </div>
</div>



app.controller('SiblingOneCtrl',
  function SiblingOneCtrl ($rootScope) {

  $rootScope.$on('rootScope:emit', function (event, data) {
    console.log(data); // 'Emit!'
  });
  
  $scope.$on('rootScope:broadcast', function (event, data) {
    console.log(data); // 'Broadcast!'
  });
  
  $rootScope.$on('rootScope:broadcast', function (event, data) {
    console.log(data); // 'Broadcast!'
  });

});

app.controller('ChildCtrl',
  function ChildCtrl ($rootScope) {

  $rootScope.$emit('rootScope:emit', 'Emit!'); // $rootScope.$on
  $rootScope.$broadcast('rootScope:broadcast', 'Broadcast'); // $rootScope.$on && $scope.$on

});


Ref.1 AngularJS Offical Document: $rootScope
Ref.2 Understanding Angular’s $scope and $rootScope event system $emit, $broadcast and $on

星期三, 10月 05, 2016

React Component shouldComponentUpdate 實作


最近朋友遇到一個有趣的React問題,可能頁面上有個值,一秒鐘會有幾萬筆資料進來,但是如果要一直更新畫面,效果不好。

這邊我推薦使用shouldComponentUpdate 來阻擋這種一秒鐘幾十萬資料變動的畫面呈現議題。

範例程式碼如下
http://jsbin.com/lilubaj

1. ParentComponent每1ms變動一次數值給ChildComponent(this.state.count)。
2. ChildComponent會在畫面上呈現(this.props.count)。
3. shouldComponentUpdate 有個timer設置每1秒才會允許畫面更新一次。
4. componentWillReceiveProps 原本的資料還是每1ms都會更新(資料流是正確的)。



星期二, 7月 12, 2016

Redux middleware 筆記

使用redux middleware完成非同步呼叫

我們團隊在開始使用action->dispatch->reducer其實進入蠻快的
但是當進入到非同步的時候就卡關了
因為要在action creator要處理非同步,如果不使用middleware
我們可能會在action creator

export function addTodo(text) {
  setTimeout(function () { 
return { type: ADD_TODO, text }
  },3000)
}
但是reducer會跟你說錯,因為回來的東西並不是action而是一個function,reducer無法處理,這時候就需要middleware處理了。


我們大概可以把 middleware當作redux流程中的一部分。

action->dispatcher->customized async middleware-> reducer 產生新的state。

============async call sample===========

var Promise = require('bluebird');
var Superagent = require('superagent');

function asyncMiddleware(){
 return function store(store){ 
   return function next(next){ //next middleware
    return function actionHandle(action){ 
    if (typeof action.ASYNC_CALL !== 'undefined') {
     return next(action); 
     //如果action沒有關鍵字ASYNC_CALL,則直接走下一個middleware
    }
    var type = action.type;
    
    return new Promise(function promiseHandle(resolve, reject){
     //這邊我們使用bluebird的Promise來達成promise
     
     function responseCallback(responseError, response){
      //some code error handle or resolve promise

      next({
       type: type,
       response: response
      });
      
      resolve(response);
      
     }
     
     //do ajax call
     //這邊我們是使用superagent 來get/put/post/delete
     Superagent.get(target).query(params).set(header).end(responseCallback);
    });
   }
  }
 }
}

=========action creator=================
而我們的action creator就很簡單了
例如下面這個是非同步呼叫載入個人資料



export const LOADED_PROFILE = 'LOADED_PROFILE';
export function loadProfile(params) {
 return {
  'ASYNC_CALL': { //有此關鍵字 middleware會走 ajax call
   type: LOADED_PROFILE,
   method: 'get',
   target: '/profile/:pid',
   params: params
  }
 };
};

=========component/container===========

import { loadProfile } from 'actions/profile';

class Profile  extends Component {
 componentDidMount() {
  var params = {};//get/post的參數 
  this.props.loadProfile(params).then(function(result) {
   //do something
  });
 }
}
var mapDispatchToProps = { loadProfile };
export default connect(mapStateToProps, mapDispatchToProps)(Profile);


=========小結=====================

透過這種方式,團隊成員在使用redux流程都會很一致的
action->(middlewares)->reducer->store

不用知道middlewares的細節就可以完成開發
(不過當然我都有解釋給他們聽原理)



=========附註======================

我們是從redux-thunk的source code理解實作方法的
https://github.com/gaearon/redux-thunk/blob/master/src/index.js
只有短短10多行程式碼

redux middleware的說明官方文件跟有人從頭跑過一次redux middleware的中文說明
http://redux.js.org/docs/advanced/Middleware.html
http://huli.logdown.com/posts/294284-javascript-redux-middleware-details-tutorial



星期日, 7月 10, 2016

React-Redux 筆記

react-redux其實概念我整理如下

  • 有個中央控管的rootStore
  • 元件把自己需要的rootStore map回去變成自己的props
  • 元件可以發出action去變動rootStore 進而更新自己的畫面


=================Store層========================
rootStore管理整個React App的資料(我們先稱他為root)
ex:

{ root : 
 profile:{...profileData},
 friend: {...friendData},
 privacy: {...privacy}
}
=================Action定義層========================
action會定義我們的操作
ex:

const ADD_PROFILE_DATA = 'ADD_PROFILE_DATA';
addProfileData(data) {
 {
 type: ADD_PROFILE_DATA,// for reducer使用
 data:data //這個action會變動的資訊
 }
}

=================Reducer定義層========================
reducer負責處理 action來的狀態變化
所以跟rootStore類似,我們會拆幾個reducer來處理


rootReducer= combineReducers({
 profileReducer,
 friendReducer,
 privacyReducer
});

const profileReducer = function (state, action ) {

  switch(action.type) //action所定義的type
    case 'ADD_PROFILE_DATA'

    state.profile = action.data
    return state; //這兩個的意義 (state, action) => new state
  
    default: 
    return state;//沒定義的action不變動state
}

=================Component/Container(view)定義層=========
React-redux的元件跟react元件最大的不同就是有引入react-redux的connect()方法。



import { connect } from 'react-redux';
import {addProfileData} from 'action/profile';
class Profile extends Component { 
//react lifecycle method, render methor
}
mapStateToProps (state) {
  profile: state.profile 
  //我的Profile只需要profile的資料
  //就map rootStore的 profile變成自己的props
  //如果今天有其他的action變動到rootStore profile的資料
  //Profile也會跟著更新狀態
}

export default connect( 
  mapStateToProps, { addProfileData } ,{/*mergeProps*/},{/*option*/})( Profile );


要熟悉react-redux 對他提供的connect一定要熟悉
第一個連接的是這個component的mapStateToPros 這個function
第二個是這個component會發出的action,官方是稱他為 mapDispatchToProps
做了上述兩個動作,這個react component就在redux資料流當中了

this.props.profile就有相對應的資料
this.props.addProfileData 也可以dispatch透過reducer,更新rootStore的資料。

第三個參數 mergeProps 第四個為option
後兩個比較少用,避免混淆觀念,我這篇先跳過,有興趣可以參閱官方API
https://github.com/reactjs/react-redux/blob/master/docs/api.md#connectmapstatetoprops-apdispatchtoprops-mergeprops-options


=================後序========================
以上是最基本的redux在react的應用流程,
之後還有要跟大家說的,如果redux會使用到非同步呼叫或是其他功能需求(ex logger),
我們是使用redux middleware來完成。

星期二, 11月 05, 2013

[公告] 網誌搬家

各位好,最近把網誌搬到 - http://kvzhuang.logdown.com/ (其實已經搬了一段時間了)。

是個很不錯的部落格,歡迎大家多多瀏覽推薦阿。

之後會把網域也一併搬過去。

星期二, 8月 06, 2013

[COSCUP] 2013 COSCUP 參與心得

  這次參加COSCUP是我第一次參加。雖然我本身專注前端技術,但是其實本次的議程我並沒有只關注前端的議題,反而到處去看 Open Data,零時政府的議題。我才發現一個感覺是,我們並不是一群關上門來寫程式的人。我們十分關注時事,關切社會。


g0v.tw 高嘉良臥病仍不忘撰寫程式碼。(圖取自 inside.com.tw)

  這次的議題到處可以看到和時事相關的議題,拆政府,國防布。CLKao也有一句讓我印象十分深刻的話"政府應該停止使用網頁點擊率當作績效的KPI,而是資料的使用率做為績效的KPI"。

  文人使用文字改變社會,程式設計師使用程式碼改變社會。 Code 不再是只有社會的高級分子,立法委員能夠撰寫,你我都能夠參與改變社會,是我這次參加活動最大的感動。

零時政府網站
如何參與零時政府 g0v hackpad

  還有我在師大資工研究所老師,中央資工副教授鄭永斌老師也上台說 Lighten talk,表達他對希望資工所甄試有所變革的期望所下的行動。都是令人十分值得推廣的。



星期四, 7月 25, 2013

[人文] 驚喜合唱 101 Flash Mob Chorus in Taipei 101, Taiwan

  最近看到朋友分享了一個驚喜合唱 101 Flash Mob Chorus in Taipei 101, Taiwan。就很想要幫忙宣傳一下,真的會令人感動的台灣情!

  大家也可以幫忙轉貼出去啊! 台灣人就是那麼熱情有感情的民族。


星期二, 6月 25, 2013

[css] units of css

  這次來介紹 css的度量衡,尺寸介紹。尺寸共有三種類型,一種是絕對數值,如 inch, cm, mm, pt(point), pc(pica), 這種和日常生活相關的尺寸。另外一種是比例上的計算,如 em,ex或 %,最後一種則是特別的單位  px 。

  首先先介紹絕對數值,基於現實生活數值,所以呈現的情況在各種裝置下將會一致,也因此不建議使用在螢幕上,原因是呈現出來螢幕的大小是很多變的,若使用固定尺寸輸出將會造成呈現錯誤。

  絕對數值的轉換公式為 1in = 2.54cm = 25.4mm = 72pt = 6pc。

  接下來來討論比例上的計算,以em當例子,若我們設定字形尺寸為 2in, 1em 就相當於 2in。 em 相關於 font-size大小,所以字體大小也影響到 em的所呈現的大小。我們也常看到 "text-ident: 1.5em" 或是 "margin: 1em"這種用法,都是配合字體大小設定所呈現的格式。下方我做了個 em實例,有機會可以去實驗看看。

Check out this Pen!

  最後介紹 px 這個特別的單位,他和上述兩個不一樣的地方是,他是基於電腦螢幕所發展出來的規格,定義在最小,但是是可以看見的一個單位下所創造出來的螢幕單位。而 px 這名字則是來自於 screen pixels。


  下面這張圖是 W3C 各種單位推薦的的使用方法。也可以參考看看。


參考資料: W3C - EM, PX, PT, CM, IN…

星期三, 6月 19, 2013

[RGBA] difference between index and alpha transparency

  今天稍微介紹一下 Index以及 Alpha 透明度的差異。首先我們先介紹 Index透明度, Index透明度我們以 GIF檔案舉例,一個 GIF檔案會分做兩部分: Color Table 以及圖像的資料。 Color Table 是一個用於此圖像的顏色列表,如果是 8-bit的 GIF圖檔,就會有2^8= 256種顏色在此 Color Table。每一個顏色都被分配一個順序的數字,如下圖表示。

  GIF圖檔對應到 Color Table的數值,而呈現 Color Table紀錄的顏色。如下例,其顏色索引是 008,而相對應的呈現的顏色就是 #d8d3de。


  在 Index透明度,每個在 Color Table的顏色都可以被設定是否要被設定為是否呈現為透明色,若指定為呈現為透明色,則輸出之後就會是透明色,如下圖。
  

Alpha Transparent
  那在討論 Alpha 透明,在 Alpha透明度,每個顏色在圖像當中都有一個 alpha的數值紀錄他的透明程度,所以他們呈現的透明程度是一種可以漸變的情況。我們可以從下面兩張使用不同透明色匯出的圖形知道差異。

GIF 索引色透明
Alpha透明

  我試著用工程師的角度解釋兩者差異,也很希望設計師朋友能以不同角度解釋補述,若有錯誤也歡迎更正。


星期二, 6月 18, 2013

[html] media object

  在 twitter bootstrap裡面有一種元件類別叫做 media object,其樣式就是一個圖像在左邊,而相對應的文字敘述在右邊。這種樣式真的現在到處在哪邊都用的到,當然若使用一些框架,單純直接遵照規定使用撰寫即可,但是如果沒有使用框架,為了之後好維護我把我自己訂的一個樣板分享出來給大家。


   Source Code: https://github.com/kvzhuang/public_html/blob/master/2013/media-object.html
  相信有更好的做法,也很歡迎各位給予意見指教。

星期四, 6月 13, 2013

[css] box model and box-sizing memo

  今天來討論入門討論 box-sizing這個css3的一個屬性,但是在知道box-sizing之前我們必須先知道什麼是 box model,這個目前在前端界很重要的概念。

  W3C的標準的 Box Model

  • Element 所占空間
  • Element 所佔空間高度 = content 高度 + padding 高度 + border 高度 + margin 高度
  • Element 所佔空間寬度 = content 寬度 + padding 寬度 + border 寬度 + margin 寬度
  • Element 實際尺寸
  • Element 高度 =  content 高度 + padding 高度+ border  高度
  • Element 寬度 =  content 寬度 + padding 寬度+ border  寬度
  IE6有特別的算法
  • Element 所占空間
  • Element 所佔空間高度 = content 高度  + margin 高度
  • Element 所佔空間寬度 = content 寬度  + margin 寬度
  • Element 實際尺寸
  • Element 高度 =  content 高度 (包含了 content,padding,以及 border)
  • Element 寬度 =  content 寬度 (包含了 content,padding,以及 border)
  我繪製了圖片,很清楚說明兩者差異如下。


    Box-Sizing

  接下來進入主題,介紹 box-sizing,他有三種屬性:  content-box,padding-box,以及 border-box。從下面的實際範例很容易可以看的出來三者的差異(感謝 Kuro提供,建議使用 Firefox瀏覽)。

Check out this Pen!


div{
    border: 10px solid #000;
    width: 50px;
    height: 50px;
    padding:10px;
    margin:10px 0;
    background-color: #fff;
}
.content-box {
  /*width = content width+padding+border*/
  /*width = 50+20+20 = 90 */
}
.padding-box {
  /*content width only 30 + padding(20) = 50*/
  /*width = 50+20= 70*/
  margin-left: 10px;
}
.border-box {
  /*content width only 10 + padding(20) + border(20) = 50*/
  /*width = 50*/
 margin-left: 20px
}
.content-box{ 
  -moz-box-sizing: content-box; 
  -webkit-box-sizing: content-box; 
}
.padding-box{ 
  -moz-box-sizing: padding-box; 
  -webkit-box-sizing: padding-box; 
}
.border-box{ 
  -moz-box-sizing: border-box;  
  -webkit-box-sizing: border-box; 
}Check out this Pen!
 
  通常元素預設為 content-box,此為保留 W3C的標準 Box Model的行為,其寬高的設定,即是內容的寬高,而元件的寬高則是再加上 padding以及 border。
 
  border-box則是會把元素的寬高計算包括 padding以及 border,所以上例設定寬度為 50px,實際上 padding左右佔掉 20px, border左右占掉20px,實際內容寬只有10px,,根據 Kuro提醒 Chrome的 input type="search" 預設為 box-sizing: border-box。

  而 padding-box則是其寬高的設定會把padding算進去,而不算border,所以設定寬度為50px,padding左右佔掉 20px實際內容寬度就只有30px了。



參考資料: Mozilla Developer Network: box-sizing


星期三, 6月 12, 2013

[html] difference between alt and title

  最近在幫人上課,有人提到, alt以及 title的差別,我稍微整理了一下。

  根據 W3C recommendation "alt"代表著 alternate text 當使用者的圖檔(img tag)如果無法讀取時,替代性會呈現的文字;或是表單輸入( input type="image"),以及 applet無法讀取時的替代文字。"alt" 在 W3C Markup Validation 是必要存在的屬性(感謝 Kuro Hsu補述)。

  而 title則比較是提供提示型的資訊。例如游標移上去的提示訊息。

  以 google search的 googlebot會比較以 "alt" 作為 SEO的搜索的資料。所以如果有想要被 Search Engine搜尋到的話,可以稍微注意一下 "alt" 屬性後面帶的值。

  下方是測試 SEO的實驗內容而已,大家可以忽略。

http://lab.kvzhuang.net/test/2013/seo-test1.html  http://lab.kvzhuang.net/test/2013/seo-test2.html

星期五, 6月 07, 2013

[life] 前端工程師的正確心態

  最近 Front-End Developers Taiwan有人在問想要成為前端工程師,其實小弟也還一直在這領域學習摸索中,抱持著分享的心態提供一些建議給想要從事這領域的朋友。


  • 首先要有追求細節以及原理的心,前端工程師本身的工作多數時間會糾結在 HTML標籤,CSS樣式,以及 JavaScript的行為。若不懂原理根本只懂複製貼上 jQuery的程式碼,卻不懂裡面的 this在每一個階段表達的意義,這樣也難怪很多人說前端工程師只是做網頁的,也是前端工程師常常被輕忽的原因,所以要知其原理而撰寫。

  • 再者要有一定的後端技術,資料庫技術。前端工程師乃是連接視覺設計師與後端工程師的楔石( Keystone),並非前端工程師就不需要知道後端的技術,資料庫正規概念,應用程式介面設計( API Design),資訊安全防護都是需要的基本常識。

  • 必要有溝通能力,由於是連接視覺與工程師的楔石與橋樑,討論是難免的。若不能夠很清楚的表達清楚在擔任前端工程師是有其阻礙的,做好良性的溝通是最重要的事情。

  • 要有實驗精神,我們面對的是極具挑戰性執行平台,五花八門的瀏覽器。而且外界對我們的期望是這些主流瀏覽器都要能夠運作的順暢,所以其實要常常對一些未知的問題做一些原型( prototype)的實驗。

  這是我一些還在學習的心得,跟大家分享。


[JavaScript] Prototype Chain

  這次延續上次的 prototype,稍微討論一下 prototype chain。這也是 JavaScript很特別的繼承方式下的方法。我參照 Professional JavaScript for Web Developers - Nicholas C. Zakas的 prototype chain的範例實作以及圖片說明如下。

function SuperType(){
  this.property = true;
}

SuperType.prototype.getSuperValue = function (){
  return this.property;
};

function SubType() {
  this.subproperty = false;
}

//inherit from SuperType
SubType.prototype = new SuperType();

SubType.prototype.getSubValue = function () {
  return this.subproperty;
};

var instance = new SubType();
window.console.log(instance.getSuperValue());Check out this Pen!


 
  我們有兩個類別 SuperType以及 SubType,都各自有其屬性跟方法。其差別在於 SubType有新增一個 SuperType的 instance並且指定為他的 prototype(Line 11)。這差異也造成三個地方要注意:

  1. 上圖有了  SubType Prototype 的 __proto__到 SuperType Prototype這個連結關係,而原本在 SuperType存在的屬性跟方法也同時存在 SubType.prototype。

  2.  getSuperValue()這方法仍然在 SuperType.prototype物件當中,那是因為我們宣告他是在 SuperType.prototype當中。而 property則會在 SubType.prototype這個物件當中,是因為他是 instance物件,隨著 new 的物件而存在,我們宣告了 SubType.prototype = new SuperType(),其 SuperType的  this就相當於 SubType.prototype (若要更加延伸探討原因可以參考 [JavaScript] Conditions of this object)。

  3. 同時也注意一點就是 instance.constructor指向 SuperType,原因是 SubType.prototype的 constructor屬性也被複寫過去而重新指向到SuperType了。

  Prototype Chaining 延展了 prototype搜尋方法跟屬性的機制,若在讀取一個 instance的屬性或方法的時候沒有被找到,會往他的 prototype繼續搜尋。在此案例當我們呼叫 instance.getSuperValue()時候會有三個搜尋的步驟: 1) instance ->2) SubType.prototype->3) SuperType.prototype。

  Default Prototypes

  在 JavaScript的 Reference Type都繼承自 Object,所以上述範例實際上會是下圖(參考Professional JavaScript for Web Developers Chapter.6 Object-Oriented Programming)。當我們呼叫 instance.toString(),實際上是呼叫 Object.prototype的 toString()方法。

  延伸閱讀: [JavaScript] Prototype Memo

  Prototype的觀念一直是 JavaScript蠻值得探討的一個話題,文章若有敘述不清楚地方歡迎大家找我討論,也歡迎大家指教補述。

星期二, 6月 04, 2013

[JavaScript] Prototype Memo

  大家好,這次來探討 JavaScript的 Prototype。老實說在很多地方都有討論這個功能,我自己本身也對這個 JavaScript使用的繼承方式想要探討一番,我用我的方式解釋一次,也希望大家不吝指教。

  首先  Prototype又稱為原型,使用方法我做了一個範例如下。左邊是沒有使用 prototype的方法,右方是使用 prototype進行的方法的差異。(感謝 Vexed的投影片指點。)可以發現使用 prototype所製作出來的 instance屬性跟方法會使用相同的記憶體區塊,這代表這當我們若改變 Person()的 prototype的內容以及方法,其 instance的值也會跟著變動。

  流程上,當上述右例的 Person()被建立的同時 (第一行 function Person (){}),他的 prototype屬性也被建立起來。其中 Prototype的 Constructor也被建立起來,並且指回 Person (如下圖),在這個例子裏面, Person.prototype.constructor 指向的是 Person。如下圖我參照 Professional JavaScript for Web Developers - Nicholas C. Zakas做了其 prototype的示意圖。


  由圖可知 Person的 prototype指向 Person.prototype,而 Person.prototype.constructor也指回 Person,形成一個LOOP。也知道被 new出來的 instance有__proto__屬性, 雖然 __proto__並不能夠直接被存取,我們可以透過 isPrototypeOf來證明上面的關係的正確與否。可以在 console試看看答案會如下。


  • Person.prototype.isPrototypeOf(p1); // true
  走過一次之後大概對 prototype有比較清楚的概念了,下次會介紹 prototype chain的概念。




星期二, 5月 28, 2013

[Git] 讓你的 Github跟公司的 Git分開

  平常我自己會用 Github放一些我做實驗的網頁工具,而公司也用 Git來做版本控管。當然第一次執行git commit的時候, git會請你輸入你的電子郵件跟姓名,這時候就兩難了。輸入公司的,Github就沒辦法有自己的紀錄在,就是在 github的 Your Contribution (很多塊綠色點點)就會是以公司的帳號而不是以你個人的帳號了,用自己的電子郵件,在公司看git 紀錄應該會被釘。

  所以可以在第一次 git commit輸入自己的,然後再到公司的下面輸入個別的公司的帳號。其指令就是。

  git config [--global | --local] user.name "Your Name"
  git config [--global | --local] user.email "yourmane@domain.com"

  --global就是全體的設定值, --local的就是個別的設定值。  你也可以手動到各個 repository的 .git下面修改config檔案。在最後加上:

  [user]
          name = Kevin Zhuang
          email = kvzhuang@gmail.com

每個 repository就有不同的帳號了。



星期一, 5月 27, 2013

[JavaScript] typeof memo

  可以使用 typeof來判斷變數宣告,以避免在某些情況下不確定此變數或 Member存在導致 JavaScript中斷。


  • if (window.android.changeId) {} 
    • 若window沒有 android或是 底下沒有changeId的方法時候,JavaScript會中斷執行
  • if (typeof window.android !== "undefined" &&typeof window.android.changeId !== "undefined") {}
    • 可正常判斷是否有此 Member或是變數。
  也可使用 typeof(window.android),作用一樣。

[Closure] JavaScript使用 Closure模擬出 Private Member

  JavaScript裡面其實並沒有 Private Member的概念,(至少在EMCAScript 4),那如果我們要實作Private Member要怎樣實作呢? 可透過 Closure來完成。

function person (){
  this.age = 10;
  this.name = "Kevin";
};
var p = new person();
console.log(p.age + ":" + p.name);

function person_closure (age, name) {
  this.getName = function () {return name; };
  this.setName = function (newName) {name = newName; };
  this.getAge  = function () {return age;};
  this.setAge  = function (newAge) {age = newAge;};
  
}
var p_c = new person_closure(10, "Kevin");
console.log(p_c.age + ":" + p_c.name);
console.log(p_c);
p_c = null;Check out this Pen!


  如上方例子第一個例子由於沒有使用 Closure來達成 Private,只要打開瀏覽器的 debugger都可以觀察的到裡面的欄位。而第二個 person_closure透過參數傳入 age以及 name也只能使用 getter以及 setter方式存取變數值,進而達到 private 變數。

  最後稍微提醒一下,Closure容易造成記憶體無法釋放的問題,在此例 age,name會一直存在記憶體。所以我最後設定 p_c = null讓瀏覽器回收記憶體。

  這是我參考MSDN JavaScript: 使用物件導向技術來建立進階 Web 應用程式所做的案例探討,也歡迎大家來信更正。

延伸閱讀: [JavaScript] Closure 概念


星期日, 5月 26, 2013

[JSDC] 【JavaScript忍之道特別企劃】JSDC心得分享

  小弟我有上報耶,雖然只有一小段而已還是很開心就是。

【JavaScript忍之道特別企劃】JSDC心得分享


小莊
JSDC志工/前端工程師

前端開發是未來的趨勢,而JSDC在促進JavaScript的產業、人才、社群的結合很努力,因此認同這些想法,才會想要投入擔任志工。這次擔任場控,雖然很忙很累,但也因此認識許多國際級的大師,收獲很多。