2012年8月28日 星期二

json2 library 介紹、載入

json2Library
瀏覽器因為版本問題,較新的版本支援JSON功能,較舊的版本沒有JSON功能,如果遇到沒有原生支援JSON序列化與解序列時就可以使用JSON2.js這個lib。

JSON2.js官方下載點


使用的時候,可以寫一段程式碼判斷JSON物件是否存在,若不存在就動態載入json2.js的library

你若是ie8可以使用開發者工具,在瀏覽器模式中選擇ie7來模擬ie7環境來測試,因為ie7沒有原生的JSON物件。


example:

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>動態載入json2</title>
<script>
(function(window,undefined){
//如果mng不存在就將其初始化一個空物件
  (window.mng || (window.mng={}));
  var mng = window.mng;
  //執行loaderJson的次數計數
  var loaderCount = 0;
  //結束執行loaderJson條件的次數
var finishCount = 5;

var loaderJson function(){
loaderCount++;
if(window.JSON){  
                        //stop
clearInterval(timer);
//alert('JSON2載入成功');
processStart();
return;
}
//如果執行了五次,300ms * 5 ,1.5秒還是無法載入成功,就停止載入
if(loaderCount === finishCount){
                        //stop
clearInterval(timer);
//alert('JSON2載入失敗');
}
};

//如果環境上沒有JSON這個物件,就動態載入JSON2.js這個library
if(!window.JSON){
var doc_head = document.getElementsByTagName('head')[0];
var doc_script = document.createElement('script');
                    doc_script.setAttribute('type', 'text/javascript');
    doc_script.setAttribute('src', "../jslib/json2.js");
      doc_head.appendChild(doc_script);
   /*每300ms呼叫一次loaderJson function,直到JSON建立,
              或是loaderCount達到finishCount的次數。   */
        var timer = setInterval(loaderJson, 300);
}else{
//代表程序中呼叫程序開始起使點
processStart();
}

function processStart(){
mng.cat = {name:'咕嘰',age:2};
                //JSON.stringify能將物件序列化成JSON字串格式
mng.strCat = JSON.stringify(mng.cat);
alert(mng.strCat);
                //JSON.parse(jsonStr),能夠將json字串反序列為對應的物件或數值。                
alert( JSON.parse(mng.strCat).name);
};

})(window);
</script>
</head>
<body>
</body>
</html>


javascript DOM 新增、刪除

javascript DOM 新增、刪除 操作

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>DOM 新增、刪除</title>
<script>
window.onload = function(){
//add element
document.getElementById('addDiv').onmousedown = function(){
var node = document.createElement("div");  //建立一個元素  
    node.style.width = "50px"; //DIV 寬度
    node.style.height = "50px"; //DIV 高度
    node.style.backgroundColor = "#FF0000"; //背景色
    node.style.border = "solid"; //邊框為實線
    node.style.borderWidth = "1px"; //邊框寬度
    node.style.borderColor = "#CCCCCC"; //邊框色彩
    //node.setAttribute("id","myDiv");  //可以用來設定元素屬性
document.body.appendChild(node);  //把元素加到body元素裡面
};

//remove element
document.getElementById('removeDiv').onmousedown = function(){
var nodes =  document.getElementsByTagName('div'); //傳回DIV element的array
//console.log(nodes);
//remove last div
if(nodes && nodes.length > 0){
//console.log(nodes[nodes.length-1]) //google瀏覽器使用
document.body.removeChild(nodes[nodes.length-1]); //刪除最後面的DIV
}
};
}
</script>
</head>
<body>
<input id="addDiv" type="button" value="add Div"/>
<input id="removeDiv" type="button" value="remove Div"/>
</body>
</html>

2012年8月27日 星期一

JavaScript Global variables的問題

JavaScript 的變數:
  • JavaScript以函數來管理作用域,定義在函數區塊內的變數是屬於該函數的區域變數。
  • 全域變數是定義在函式作用域外或是沒經過宣告就直接被使用的變數。
  • 一般我們所接觸的執行環境中全域變數指的是指window上的屬性。

全域變數的問題:
  • 程式中的程式碼會共用全域變數,他們存在於相同命名空間中,非常容易發生衝突。
衝突原因:
  • 使用第三方的javascript lib。
  • 團隊其他成員或廣告合作夥伴所撰寫的程式碼。
  • 第三方用來追蹤分析使用者操作的程式碼。
  • 其他等等等等
這些程式碼或lib都有可能使用到同名的全域變數,例如以前的IE7並沒有winsow.JSON這個全域物件,所以我們會抓取網路上知名的lib JSON2來處理JSON的序列化與解序列化問題,但是到了IE8卻原生支援了JSON物件,如此反而會造成衝突使得程式發生錯誤。

因此我們因該盡量避免使用全域變數,使用的越少越好。

note:在宣告變數時,要養成使用var宣告的習慣。

JavaScript 正常使用下如:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Javascript Global Variables</title>
<script>
console.log(this); //window
console.log(window); //window
console.log('this === window 結果:' + (this === window)); //true
console.log("window.hasOwnProperty('name')= " + window.hasOwnProperty('name')); //true

//Dog is Class
function Dog(){
this.color = '白色'; //public Property
var name = "小米"; //private Property
this.getColor=function(){
    return this.color;
};
this.getName=function(){
return name;
};
}

//cat is function
function cat(color ,age, name){
var color = color;
var name = name;
return {color:color, name:name};
}
//create Dog instance
var myDog = new Dog();

console.log('myDog.color= ' + myDog.color); //白色
console.log('myDog.getColor()=' + myDog.getColor());//白色
console.log("window.hasOwnProperty('color')= " + window.hasOwnProperty('color'));  //false
console.log('window.color= ' + window.color); //is undefined 
console.log('myDog.getColor.apply(window)= ' + myDog.getColor.apply(window));
window.color = "橘色";
console.log('window.color= ' + window.color); //橘色
console.log('myDog.color= ' + myDog.color); //白色

//javascript的this是看呼叫function的人是誰,而apply會指定呼叫者,所以會改變了this。
console.log('myDog.getColor.apply(window)= ' + myDog.getColor.apply(window)); //橘色
console.log('myDog.getColor= ' + myDog.getColor()); //白色

console.log('myDog.name= ' + myDog.name); //這是private Property 所以取不到, is undefined.
console.log('myDog.getName()= ' + myDog.getName()); //小米

console.log('window.name=' + window.name); //is empty string 


//get cat
var myCat = cat('黑色','咕嘰');
console.log('myCat.color' + myCat.color);
console.log('window.color=' + window.color);
</script>
</head>
<body>
</body>
</html>


JavaScript誤用造成全域變數生成的範例:

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Javascript Global Variables</title>
<script>
console.log(this); //window
console.log(window); //window
console.log('this === window 結果:' + (this === window)); //true

//function mobile
//false
console.log("window.hasOwnProperty('bookName')= " + window.hasOwnProperty('bookName')); 
//false
console.log("window.hasOwnProperty('bookWeight')= " + window.hasOwnProperty('bookWeight'));
//false 
console.log("window.hasOwnProperty('author')= " + window.hasOwnProperty('author'));
//Book is Class
function Book(bookName , bookWeight , bookAuthor){
var bookName = bookName;      //private Property Local variable
this.bookWeight = bookWeight; //public Property Local variable
author = bookAuthor;       //* author is globa variable
this.getName=function(){
    return bookName;
};
this.getWeight=function(){
    return this.bookWeight;
};
this.getAuthor=function(){
    return author;
}
}

var myBook = new Book("深入淺出JavaScript" , '1kg' , '麥克先生');
//false
console.log("window.hasOwnProperty('bookName')= " + window.hasOwnProperty('bookName')); 
//false
console.log("window.hasOwnProperty('bookWeight')= " + window.hasOwnProperty('bookWeight'));
//true 
console.log("window.hasOwnProperty('author')= " + window.hasOwnProperty('author'));

console.log('myBook.getName()= ' + myBook.getName()); ///深入淺出JavaScript
console.log('myBook.getWeight()= ' + myBook.getWeight()); //1kg
console.log('myBook.getAuthor()= ' + myBook.getAuthor()); //麥克先生


//function mobile
console.log("window.hasOwnProperty('type')= " + window.hasOwnProperty('type')); //false
console.log("window.hasOwnProperty('price')= " + window.hasOwnProperty('price')); //false

function mobile(type,price){
        //會因為使用方式沒注意而變成全域變數
this.type = type; //注意這個this是看誰呼叫這個function決定的,所以有可能會變成全域變數
var price = price;
return {type:type,price:price}
}
//注意這個function是直接呼叫而非使用new,這樣他的this會依呼叫者變化
var myMobile = mobile('IPhone4S' , '18000'); 
console.log("window.hasOwnProperty('type')= " + window.hasOwnProperty('type')); //ture
console.log("window.hasOwnProperty('price')= " + window.hasOwnProperty('price')); //false
</script>
</head>
<body>
</body>
</html>


JavaScript不良特性,會造成開發者不小心的全域變數生成:

function area(pi , redius){
   return  result = redius * redius * pi;
}
如此,result因為沒有使用var宣告到,將會變成全域變數。


function init (){
    var eclipseX = cubeX = 10;
}
因為等號是右結合會從右邊先運算所以會等同是,var eclipseX = (cubeX = 10);,如此cubeX未被宣告就被賦值,因JavaScript的特性關西將會變成全域變數。


關於var宣告全域變數的差別:

  • 使用var宣告的全域變數(在function外宣告),是不可以使用delete運算符號刪除的。
  • 非使用var宣告的全域變數(不小心在函式中未宣告var創造出來的)是可以使用delete來刪除。

參考資料來源:
JavaScript 設計模式  (oreilly公司)

關於Console的使用方式請參考http://program-rock.blogspot.tw/2012/08/chrome-developer-tools-console.html