2014年6月25日 星期三

Javascript Enlightment Memo 深入精要筆記

Chapter 1 - Javascript物件

* Function接(),會產生一個執行物件(function return後如無參考,則會被GC),並會傳回這個function的return value
* Function冠用new(此時稱此function為建構函式),會產生一個執行物件,並傳回這個物件
* function(){return {ID: 1}}() 跟 new function(){this.ID = 1} 都會傳回一個物件,差別是前者不會有prototype繼承
  - 是嘛?在Chrome裡都有耶? 
* 尚未明白為何的地方:
  - Function裏面有return,執行物件可以接()執行!!
  - Function沒有return,就只是執行物件

* 九大原生物件
  - Number, String, Boolean, Array, Object, Function, RegExp, Date, Error
* 原生物件標準需由new運算子產生,但可用字面值(Literal)來產生
  - var n = 1
  - var s = "string"
  - var b = true
  - var a = [1,2,3]
  - var o = {ID: 1}
  - var f = function(){}
  - var r = /.*/

* 值分為原始值(Simple Value)與複合值(Complex Value)
  - 原始值
    - 複製:完全複製
    - 比較:比較其值
    - 屬性:沒這檔事
  - 複合值(就像指標啦)
    - 複製:僅複製參考
    - 比較:比較參考
    - 屬性:可以加入屬性

* 原始值包括6類:
  - null
  - undefined
  - "string"(雙引號字串)
  - 123(單純的數字)
  - true
  - false

* 當使用Literal產生Number, String, Boolean時,得到的是原始值(Simple value)

* Number, String, Boolean
  - 需特別注意當產生方式不同時(原始值/複合值),行為有所不同

* 物件的Constructor是"指向"他的建構函數
  - 所以判斷物件類型的方法之一是比對Constructor是否為某個函數


Chapter 2 - 應用物件與屬性

* Complex Value的屬性可以是大部分的js value

* 可以亂裝(就JSON)

* 屬性可以透過obj.prop或obj['prop']存取
 - 括號法功能較強:
    - 屬性名稱可以由字串組合
    - 屬性名稱可為數字或保留字, ex:  obj['123'], obj['object']
* 從物件中移除屬性用delete

* 尋找屬性:原型鍊(Prototype Chain) (就是繼承鍊!)
  0. 目前物件為obj
  1. 先找obj下面
  2. 再找obj.constructor.prototype
  3. 再找obj.constructor.constructor.prototype
  4. 都沒有,回傳undefined

* hasOwnProperty() v.s. in 運算元  (注意屬性在此是以名稱(字串啦)來詢問)
  - hasOwnProperty()
    - 若為true,表示屬性不是從原型鍊來的。
  - in
    - 若為true,表示該物件的原型鍊找的到該屬性。

* 尋訪屬性,可使用 for-in loop
  - 會列出包含原型鍊內的所有屬性。可用 hasOwnProperty()檢查
  - 只會列出可列舉的(enumerable)的屬性,可用propertyIsEnumerable()檢查

* Host物件
  - 非javascript標準內的物件,ex. 瀏覽器提供的,
  - 其中必有一個Head物件,也就是環境物件, ex. window


Chapter 3 - Object()

* new Object()可填initial value,物件會成為該value所屬原生物件的物件

* 繼承鍊的源頭Object.prototype (注意Object不是實體)


Chapter 4 - Function()

* 函數:一個陳述式的執行範圍

* 在函數名稱後加上()代表執行此函數

* new Function(arg1,...., argn),可吃n個參數,前面是建構出的Function的參數,最後一個是函數內容的字串
  - var func = new Function('a', 'b', 'return a+b')
  - var func = function(a, b) {return a+b}

* 上面那種作法會用到eval()造成運算浪費

* 沒有指定return的函式會回傳undefined

* arguments
  - 所以函數可以不給定指定的參數
  - 也可以給沒指定的參數
  - arguments.callee指向函數本身
  - arguments.length是函數被呼叫時得到的參數量 (1.4之後Deprecated,只能arguments.callee.length取得函數指定的參數數量)

* this
  - 這個函數屬於那個物件
  - 若是Global,則指向環境物件

* length
  - var func = function(a, b , c){} 則 func.length === 3
* 函數建立4種方式
  - var funcConstructor = new Function('a', 'b', 'return a+b');
  - function funcStatement(a, b) { return a+b; }
  - var funcExpression = function(a, b) { return a + b; }
  - var funcNamedFunction = function funcNamedFunction(a, b) { return a + b; }

* 函式使用4種方式
  - 當函式執行,就是加上()來執行
  - 當方法執行,一樣是()
  - 當建構式使用,配合new
  - apply()或call(),用途是改變所屬物件(也就是this)

* function aaa(){} 沒有aaa就叫匿名函式

* 可以無限巢狀

* 函式可以當作參數傳入函式,也可以當作return value被回傳

* Javascript執行前會解譯程式,所以可以在函式宣告之前使用函式

* 函式可以遞迴呼叫


Chapter 5 - Head/Global 物件

* Head物件包含所有的物件,透過範圍鍊所有地方都可以呼叫Head物件的成員,故就像全域屬性一樣

* 參考Head物件
  - 直接參考其名稱(ex. 瀏覽器是window)
  - 在全域範圍內使用this

* 在全域範圍中進行宣告,用var不用var有些微差異
  - 用var 是屬性
  - 不用  是變數

* 因為Head是範圍鏈的最後一站,所以他可以是隱式的。通常使用Head物件的成員不會明確參考Head物件
  - window.alert()
  - alert()  <-- br="" clear="none" usually="">


Chapter 6 - this關鍵字

* this參考到函式所在的物件
  - 例外:使用new、apply()、call()

* 巢狀函式內,this
  - ES3:this會迷失,而指到Head
  - ES5:會正常指到應該的物件

* 常用that來避免this迷失

* apply()跟call()可以指定this的值

* 當使用new呼叫函式時,this會參考到等等要被new出來的物件
  - 如果不用new呼叫,那就會在函式所屬物件產生新的屬性。(通常就是window了XD)

* 在prototype中的函式參考到this,this會指向實際的instance,而不是prototype


Chapter 7 - 範圍與Closure

* Javascript的Scope有:
  - 全域範圍
  - 函式範圍
  - eval()範圍

* Javascript沒有區塊範圍( {} )

* 以var宣告的變數會是在當前範圍內宣告,沒有用var宣告的會被宣告在全域範圍

* 若同樣的變數名稱在不同的範圍內,會傳回最近的那個值

* 範圍鍊是在"定義"函式時決定的,而非在呼叫過程中決定
  - 這就叫作語彙範圍(Lexical Scoping)


Chapter 8 - 函式原型屬性


* 預設的prototype是一個Object()物件

* Firefox2+/Safari/Chrome可以這樣參考prototype
  - obj.__proto__

* EMCA標準參考方式
  - obj.constructor.prototype

* Prototype鍊會傳回第一個找到的屬性,所以會有屏蔽效應

* 若是修改A物件預設的prototype,那用A物件new出來的物件其constructor不會是A(),而是Object()
  - 要避免必須在a的prototype內加入constructor為a

* prototype鍊是動態參考的,所以當你修改了prototype的內容,所有的Instances都會參考到最新的內容

* 但若直經更換整個prototype,現有的Instances還是會參考到舊的prototype

* 一旦建立Instances了,就不該更換prototype,避免物件有不一致的行為

* prototype繼承鍊的原始用意是要摹仿傳統物件導向的繼承機制


Chapter 9 - Array()


* Array(1,2,3)會建立一個長度為3且初始值分別為1,2,3的陣列
  但Array(5)則會建立一個長度為5的空陣列

* 透過更改length屬性,會讓Array實質的長大或變小

* 陣列裏面可以存放陣列,而有多維陣列的行為

* 向後尋訪陣列
  var count = 0
  while (count < arr.length){
    count++;
  }

* 向前尋訪陣列
  var count = arr.length
  while(count--) {
  }


Chapter 10 - String()

* a = "abc"; typeof a是String
  a = new String("abc"); typeof a是Object  (!!!!)


Chapter 11 - Number()

* 第1點跟String一樣,請使用Literal產生Number避免typeof變成Object

* 可以使用hex或oct表達法
  - var a = 0xff   //a = 255
  - var b = 012  //a = 10


Chapter 12 - Boolean()

* 第1點,一樣, String()/Number()/Boolean()都有這個問題

* var a = new Boolean(false); console.log( a ? "true" : "false"); 會log true。WTF

* 0, -0, null, false, NaN, undefined, ""會被轉換成false,其他都是true


Chapter 13 - 使用原始字串、數字、布林值


* 原始值在存取時,會變轉換成物件,提供該物件的屬性。完成屬性的存取後,該物件就會被捨棄,又變回原始值

* 如果要直接存取數字原始值的屬性,必須在被轉換成物件之間對數字賦值(evaluate),例如 1..toString()  (<- br="" clear="none">
  (這超不懂的,WTF)

* 避免使用new建構式產生原始值,避免typeof變成Object()


Chapter 14 - null


* null用來表示某個屬性存在,但沒有值

* 檢驗null,請用 ===
  - typeof 會是 Object()
  - ==無法區分null與undefined


Chapter 15 - undefined


* 用途一:表示一個變數尚未被賦值

* 用途二:表示一個屬性不存在(包括在繼承鍊裡也找不到)

* 不該自行把某變數賦值為undefined,因為此時你宣告了變數了,他不是不存在,只是空值,應該要給null


Chapter 16 - Math


* Math是特別的內建物件,無法用他產生instance,因為他沒有建構式

* Math內大寫開頭的常數屬性,無法改變他們的值

沒有留言: