【原創教程】JavaScript詳解之語法和對象

JavaScript的好的想法:函數、弱類型、動態對象和一個富有表現力的對象字面量表示法。
JavaScript的壞的想法:基於全局變量的編程模型。
 
好了,無論他是好的仍是壞的,都是個人最愛,下面直接上幹活:
1、JavaScript語法
 
一、空白:空白能可能的表現形式爲格式化字符或註釋的形式。
     有些空白不能省,有些空白能夠被移除。
     註釋,/*多行註釋*/,不建議在代碼塊中間使用這種註釋,由於可能會出現語法錯誤,因此多行註釋對於被註釋的代碼來講是不安全的。
好比:
/*
     var r_m_a = /a*/.match(s);
*/
這就致使了一個語法錯誤,因此建議避免使用/*  */註釋,而改使用//單行註釋來註釋代碼。
那麼多行註釋在何時使用呢,在對一個方法或者其餘代碼塊進行語言說明其用途和做者等信息時候使用,好比:
/*返回兩個數的和*/
function sum() {.......}
 
二、標識符
標識符由字母、數字或下劃線組成的。標識符不能使用下面這些保留字:
abstract
boolean break byte 
case catch char class const continue 
debugger default delete do double
else enum export extends
false final finally float for function
goto
native new null
package private protected public
return 
short static super switch synchronized
this throw throws transient true try typeof
var volatile void
while with
在這個列表中的大部分保留字js都沒有使用,這裏列出了這麼多,你不須要去刻意記憶,用的時候注意下,同時在編譯出錯的時候可以知道爲何出錯了。
 
三、數字
int float double?不不不,JavaScript中只有單一的數字類型,它在內部被表示爲64位的浮點數。因此1和1.0是同樣的。
其中有些特殊的數字:
     值NaN是一個數值,他表示一個不能產生正常結果的運算結果,NaN不等於任何值,包括他本身,是的沒錯,他本身都不等於他本身,你還但願誰和它相等呢。那如何檢測一個變量是否是NaN呢,用函數isNaN(number)來檢測NaN,返回Boolean值;
     值Infinity表示全部大於1.77.....e+308的值,便是無窮大。那無窮小呢,加個負號唄。
數字擁有方法,例如:Math.floor( number ) 發放將一個數字轉換爲一個整數。
這裏有一個須要注意的點,就是數值類型不含有方法,數值對象纔有方法,什麼是數值類型呢,像1233,231,34等這些都是數值類型,而若是 我這樣來:
var  num = 234.567;
這時候mun就是數值對象,它擁有方法。
 
四、字符串
字符串字面量能夠被包圍在單引號或者雙引號中,\ 是轉義字符。JavaScript在被建立的時候,Unicode是一個16位的字符集,因此全部的字符都是16位的;字符串是沒有字符類型的。要表示一個字符,只須建立僅包含一個字符的字符串便可。
上面有說到「轉義字符」,那麼什麼是轉義字符呢,轉義字符容許把那些正常狀況下不被容許的字符插入到字符串中,好比反斜線、引號和控制字符。 \ u 約定容許指定用數字表示字符碼位。
"A" === "\u0041"
字符串有一個length屬性,例如:「skylor」.length 是6.
還有一點是須要注意的,字符串是不可變的,一旦字符串被建立了,就永遠沒法改變它。可是經過 + 運算符去連接其餘的字符串從而獲得一個新的字符創是很容易的一件事。   且:::兩個包含着徹底相同字符且字符順序相同的字符串被認爲是相同的字符串。so:
's' + 'k' + 'y' + 'l' + 'o' + 'r' === 'skylor'
這是個true!一樣的 字符串也有一些方法。 
 
五、語句
六、表達式
     字面量(好比字符串或數字)、變量、內置的值(true、flase、null、undefined、NaN和Infinity)、以new 前導的調用表達式、以delete前導的屬性存取表達式、包在圓括號中的表達式、以一個前綴運算符或者是後面跟着運算符、函數調用、屬性存取表達式等。
     運算符的優先級,這裏就不說了。
     
七、函數
function關鍵字定義的大括號抱起來一段代碼: function + 函數名 + (+ 參數 +) + { }抱起來的代碼段; 
function fn(args ) {
     //函數要實現的功能代碼;
}
也能夠把函數賦值給一個變量:
var fn = function(args){
     //函數要實現的功能代碼;
}
這兩個是有區別的;後面再詳細說明。
 
2、對象
 
一、對象字面量
var empty_object = {};
 
var  blog_name = {
     "first-name": "Skylor",
     "last-name": "min"
}
對象字面量是能夠嵌套的;
 
 
二、檢索
兩種方法:
[]  通常用中括號的狀況是,後面字符串是一個數字,或者是非合法標識符,或者是個變量等
.  通常用點的狀況是,它是一個合法的JavaScript標識符且並不是保留字。
兩個均可以用的時候,推薦用 . 點表示法,由於它更緊湊且可讀性更好。
 
三、更新
 
對象中的值能夠經過賦值語句來更新。若是有就更新,若是沒有就擴充。
 
四、引用
 
對象經過引用來傳遞,它們永遠不會被拷貝。這裏有必要講下拷貝,JavaScript的拷貝咱們分爲淺拷貝和深拷貝。下面咱們來談談JavaScript中的淺拷貝以及深拷貝。
首先咱們來看看淺拷貝:
什麼是淺拷貝,就是對於有嵌套對象的對象進行拷貝的時候,只拷貝了一層,對象裏面的Array、object等嵌套的對象都不拷貝過來。簡單的沒有嵌套對象的對象,咱們用淺拷貝是沒有問題的,對於複雜點的對象,就出現大問題了。下來咱們來看一個具體的例子:
var original = {
     num: 1,
     str: 'old string',
     obj: {
          obj_1: "old obj_1"
     },
     arr: [
         "array string",
           {
               arr_obj_1: "old arr obj 1"
          } 
     ]
}
看上面的這是一個比較複雜的對象,對象的裏面包含了對象和數組。咱們來構建一個拷貝函數:
var extend = function(result, source){
     for(var key in source) {
         result[key] = source[key];
     }
     return result;
}
好,有了這個拷貝函數,下面咱們來測試下程序:
var copy_original = extend({}, original);
copy_original.str = "new String";
copy_original.obj.obj_1 = "new obj tring";
copy_original.arr[1].arr_obj_1 = "new Array obj String";
copy_original.arr[0] = "new Arrat string";
 
以上,咱們是否是隻改變了咱們拷貝過來的copy_original的值啊,那麼此時原來的對象ofiginal是否是應該仍是原來的值,咱們來運行看看就知道了{動手啊,必定要動手}。此時只有str和num保持不變了,其餘的和咱們拷貝後的對象修改後的值同樣了。
這樣看來,若是咱們不想改變原來的對象,咱們須要對對象裏面的對象和數組須要特殊待遇一下,固然咱們要給她們兩特殊照顧,就得先認識她們,下面是認識她們這兩個美女的函數:
 
var is = function (obj,type) {
 
  var toString = Object.prototype.toString;
 
  return (type === "null" && obj === null) ||
 
    (type === "undefined" && obj === undefined ) ||
 
    toString.call(obj).slice(8,-1) === type;
 
};
類型識別,用來認識對象和數組來着,有人要說了不是有typeof嗎,typeof是不可靠的,由於Array會返回'object'。好,認識了她們,咱們再來處理,怎麼樣才能深拷貝呢,咱們的深拷貝函數應該擁有處理特殊處理值爲對象或數組的鍵值對。 對於它們,程序會爲目標對象先建立一個新對象與數組,而後再一層層拷下去。咱們能夠看到它並無用hasOwnProperty,換言之,連原型中可遍歷的屬性都給它翻個底朝天。這樣一層層的拷貝下去,因而便有了下面的(性能比較差,通常狀況下線上項目謹慎使用):
 
 var deepCopy = function(result, source){
 
        for(var key in source) {
 
          var copy = source[key];
 
          if(source === copy) continue;  //如window.window === window,會陷入死循環,須要處理一下
 
          if( is(copy,"Object") || is(copy,"Array") ){
 
            result[key] = deepCopy(result[key] || {}, copy);
 
          } else {
 
            result[key] = copy;
 
          }
 
        }
 
        return result;
 
      };
 
能夠用這個深拷貝函數來實踐下上面相似的測試程序,得出結論,你便知曉了一切。關於JavaScript的淺拷貝和深拷貝網上的各式各樣,但萬變不離其宗,知道了爲啥,你就能寫出屬於你本身的deepCopy function。
 
五、原型 prototype
 
每一個對象都連接到一個原型對象,而且它能夠從中繼承屬性。全部經過對象字面量建立的對象都連接到Object.prototype 這個JavaScript中標準的對象上。
 
六、反射
 
檢查對象並肯定對象有什麼屬性是一件很容易的事,只要試着去檢索改屬性並驗證取得的值,typeof這個操做符,沒錯,是操做符,對肯定屬性的類型頗有幫助。須要注意的是typeof,原型鏈中的任何屬性也會產生一個值,有兩個方法去處理這些不須要的屬性:
     第一個是讓你的程序檢查並剔除函數值。
另外一個方法是使用hasOwnProperty 方法,若是對象擁有獨有的屬性,他將返回true,hasOwnProperty方法不會檢查原型鏈。
ex.hasOwnProperty('number');   //true
ex.hasOwnProperty('constructor'); // false
 
七、枚舉
for in 語句可用來遍歷一個對象中的全部屬性名,上面的深拷貝函數咱們就有用到了,該枚舉過程將會列出全部的屬性-----包括函數和一些你可能不關心的屬性,全部有必要過濾掉那些你不想要的值。最爲經常使用的過濾器是hasOwnProperty方法,以及typeof來排除函數:還有一點須要注意的是for in 語句對屬性名出線的順序是不肯定的,這一點須要注意下。
 
八、刪除
delete運算符能夠用來刪除對象的屬性,會益處對象中肯定包含的屬性,它不會觸及原型鏈中的任何對象。
有一點須要注意的是,你刪除了對象的屬性可能會讓來自原型鏈中的屬性浮現出來。
 
好,這節課咱們講了JavaScript的基本語法和對象的一些詳細內容,後面有些須要多多練習,修改代碼調試。咱們下期見。
相關文章
相關標籤/搜索