2014年1月2日 星期四

JavaScript 基礎訓練

在 2013/12/28 聽了保哥開的前端工程訓練的課,紀錄整理一些觀念供日後複習。


JavaScript 是物件導向程式語言。主要分為物件型別與原始型別。

只有下列5種是原始型別 (Primitive Type),其餘都是物件型別。

  • 數值 (number)
  • 字串 (string)
  • 布林 (boolean)
  • null
  • undefined

物件型別與原始型別最大的差異就是可擴增屬性。

  • 物件型別可無限擴增屬性

  • 原始型別無法擴增屬性

JavaScript 物件可看成容器。
容器裡面包含屬性 (Property) 或方法 (Method)。


JSON 合法格式 Key 與 Value 必須以雙引號(")做分隔
我們來看看有以下程式碼片段,請問輸出為何 ?


通常我們看到重複宣告變數直覺性的覺得這變數被洗掉了,
那我們繼續看看結果。



你沒看錯,JavaScript 語言特性並不理會你重複宣告一模一樣的變數,
除非你去 assign 一個值給它才會真正的改變掉裡面的值。

區別物件、變數與型別的關係

  • 物件
    具有回收概念
    記憶體中的資料
    僅存在於執行時期
  • 變數
    沒有回收概念
    儲存物件的記憶體位址 ( 指標 )
    在開發時期進行宣告 ( var )
  • 型別
    標示物件的種類
    不同型別有不同的預設屬性與方法

那物件與屬性之間又有什麼關係呢 ?
直接來看程式碼片段會比較了解。



可以清楚看到 test 變數是物件型別,前面講過物件型別可無限擴增屬性,
所以擴增了 3 個屬性分別是 name、age 與 demo。
當然如果你擴增的屬性不是原始型別,你就可以繼續擴增下去。

判斷屬性是否存在 ?


除了建議用法外還需要注意 繼承屬性 的判斷。

原始型別包裹物件 ( 不良部分 )

  • Number
  • String
  • Boolean

由於原始型別無法自由擴增屬性,
但 JavaScript 原始型別實作繼承原始型別包裹物件
可以透過原始型別包裹物件來讓原始型別自由擴增屬性與方法。
直接看程式碼片段會更為了解。



比較變數時應該注意的陷阱與扼要
切記物件是無法比較等式的。
這裡我直接分享保哥的文章 : 前端工程研究:關於 JavaScript 中物件的 valueOf 方法

原始型別
數值 (number) :


可以清楚看到就算轉型失敗成為了 NaN 但是使用 typeof 去看型別還是屬於 number 原始型別。
轉貼兩篇文章連結介紹 parseInt() :
JavaScript 快速導覽 - 內建 parseInt() 函數
傳說中 JavaScript 的 parseInt('08')
number 轉型方法與使用技巧


這邊的範例舉例說明一下,JavaScript 中每個變數都可以表現得像一個物件。
在許多型別下經常看到共通方法 toString() 這個 Method,使用如下 :


一個常見的誤解就是字面值(literal)不是物件。這是因為 JavaScript 編譯器的一個錯誤,
它試圖把 點操作符 解析為浮點數的字面值的一部分。
有其他的方法可以讓數字的字面值看起來像個物件。


分享一個整理不錯 JavaScript 基礎觀念的文章連結與 toString() Method 參考手冊。
JavaScript 庭院
JavaScript toString() 方法
string 轉型方法與使用技巧


在使用 Number() 或 String() 如果運算符 new 一起使用時,和沒有使用運算符 new 差異在哪 ?
這邊直接提供 W3School 連結 (看返回值有介紹差異性):
JavaScript Number 对象参考手册
JavaScript String 对象参考手册
W3School 還有其他許多相關資訊與操作方法可以參考。

boolean 轉型方法與使用技巧



使用 Boolean() 方法也要注意返回值是不是跟預期的一樣。
如果不確定返回值可以自己實作或是參考 W3School。
JavaScript Boolean 对象参考手册
比對 - 隱含比對與明確比對


  • == 或 != ( 隱含比對,會引發自動轉型 )
  • === 或 !=== ( 明確比對 )
  • 一律使用 === 或 !=== 比對
    ( 避免 falsy value 判斷 )
  • 使用 !! 強迫引發自動轉型
    var a = !!(0);
    bar b = !!("0");
上述有提及 falsy value,在 JavaScript 中 falsy value 代表什麼意思呢 ?
Falsy values in Javascript
直接看以下程式碼片段 :



那繼續往下看結果。


剛剛的連結裡面有 falsy value 測試,這裡直接貼出結果。
如果存有懷疑直接實作就能了解了。



結論就是在比對的時候必須要非常的小心或是使用明確比對就可以排除非預期的結果。

宣告變數可使用 Falsy 特性來避免重複宣告變數。


JavaScript 原始型別 : 空值 ( null )

  • null 是一個物件 ( 但又不算一個真正的物件 ),不是真的 NULL
  • 所有的 null 物件都是連結到系統唯一的一個 null 物件
  • null 物件永遠不會執行回收
  • 不使用 typeof obj === null 為判斷依據


JavaScript 原始型別 : undefined

  • 可以是一個內建型別
  • 可以是 undefined 值
  • 可以是一個全域變數 undefined
    window.undefined === undefined // ture
    IE8 以下此變數可重新指派或其他別物件
  • 無論是 null 或 undefined 都會隱含轉型成 false

分享一篇 null & undefined 差異的文章
javascript中的null與undefined的差異
JavaScript 原生物件 ( Native Objects )
ECMAScript 標準中定義的物件型別

  • 使用者定義物件型別
    var obj = {};
  • 內建物件型別
    Array , Date , Math , RegExp , Number , String , Boolean , Object

宿主物件 ( Host Objects )
由 JavaScript 執行環境額外提供的物件

  • window ( Browser ) , 所有 DOM 物件 ( Browser )
  • global ( Node.js ) , process ( Node.js )

這邊提供一個觀念,在建立物件的時候盡量都使用物件實字 ( Object Literal ) 建立物件。
不建議使用建構式函式去建立物件。
[JavaScript] 談物件, 實字與建構式
JavaScript 物件初探
JavaScript 基礎物件概念

  • 所有物件資料都從根物件開始連結


從根物件連結出來的變數無法被消滅,只有在程式執行週期結束後才會被回收。如果變數宣告得越多那之後嵌入的第三方元件或 Code,容易造成衝突覆蓋,之後會再探討如何減少全域變數 ( 汙染 )。

JavaScript 物件看做容器
將物件當成容器並實作出虛擬的命名空間,可以減少全域變數。


函式物件 (function)
function 可以看做特殊物件。




  • JS的一級物件 (first-class object)
    可以被動態建立
    可以指定給變數,也可以複製給其他變數
    可以擁有自己的屬性或方法 ( 物件特性 )
  • 提供了變數的作用域 (scope)
    不以區塊 {} 建立作用域,與其他程式語言不同的地方。



函式表示式 (function expression)


函式宣告式 (function declaration)



宣告變數

  • 請一律透過 var 宣告變數 ( 最佳實作 )
  • 變數宣告會讓物件自動成為物件容器的屬性

區域變數

  • 區域變數的範圍是靠 function 區隔的 ( 並非以大括號當作範圍 )
  • 宣告變數時,會成為內部物件的屬性 / 變數

全域變數

  • 亦即根物件 ( Root Object) 的屬性 / 變數
若忘記使用 var 關鍵字宣告,則是全域物件的一個屬性 ( 全域汙染 ),屬性可以透過 delete 運算子刪除。


分享一篇宣告全域變數副作用的文章
JS全局变量的副作用

JavaScript Hoisting ( 提升 ) 特性
JavaScript 的變數聲明具有 hoisting 機制,JavaScript 引擎在執行的時候,會把所有變數的聲音都提升到當前作用域的最前面。
這邊不多做詳述,提供連結文章
JavaScript 变量声明提升 (hoisting)
立即函式 (Immediate Function)
需求 : 限制變數存在的作用域 (scope) & 讓變數不輕易成為全域變數
範例 : 函式宣告式 + 匿名函式



回呼模式 (Callback Pattern)

  • 將函式當成參數傳遞給其他函式
    function text(argument1, callback){
      var  theDemo = DoSomething(argument1);
      callback(theDemo);
    }
  • 以具名函式方式傳入
    function callback(data){
      alert('Loading');
    }
    get('../API/text.html', callback);

閉包 (Closure)

  • 特性
    在特定函式中存取另一個函式的變數
    外層函式宣告的變數可以在內層函式中取得
    作用域鏈結 (Scope Chain)
  • 閉包的程式碼外觀
    運用在巢狀函式的定義中
建構式 (Constructor)

  • JavaScript 沒有 Class,不用事先建立藍圖即可建立物件。
  • 建構式即是函式,又稱建構式函式。
    var Car = function (name){
      this.name = name;
      this.slogan = function (){
        return 'Drive by : ' + this.name + '.';
      }
    }

透過建構式建立物件

  • 使用 new 關鍵字


建構式函式在建立物件時的執行過程




  • 若要在建構式 return,必須是物件型別,不能為原始型別


原型物件 (Prototype Object)

特性 :

  • 只有函式物件才擁有公開的原型物件
  • 所有其他物件僅擁有私有的原型物件
  • 代表物件實體上層物件 ( 父物件 )
  • 所有物件實體會自動繼承原型物件 : 目的在於建立物件之間的鏈結關係


constructor 方法 :

  • 預設會等於建構式函式 ( 也可以改掉 )


建立物件並繼承其他物件


prototype 與 constructor
prototype ( 函式公開屬性 ) 與 __proto__ ( 物件內部屬性 )
  • 設定物件繼承專用
  • 有所謂的 原型鏈結 (prototype chain) 觀念
  • IE 瀏覽器無法存取 __proto__ 屬性
constructor
  • 此建構子跟我們理解的建構子不一樣,並不會執行任何程式
  • 僅僅是個名稱
  • JS 物件的 constructor 屬性,僅供參考




原型鏈結 (prototype chain)
鏈結順序 :

  • 物件本身擁有的屬性
  • 物件內部 __proto__ 物件的屬性
    繼承自 prototype 的屬性
    接著會一直不斷往上層物件 (__proto__) 找下去,直到最後遇到 Object 物件為止



根物件 != Object

  • scope chain 跟 prototype chain 是完全不同的東西

檢查物件屬性是否來自原型物件 : hasOwnProperty()
理解 hasOwnProperty() 的作用



物件繼承的寫法

在物件繼承的時候若不將 constructor 指向原本自己為建構式,
則在新物件使用 .constructor 查找會指向繼承的 constructor 導致混淆.



instanceof 運算符

JavaScript instanceof 運算符深入剖析

先前有介紹過 typeof, instanceof 與它相似但是, 可以用來確認對象為某特定類型,
在此我們可以用來檢查是否從特定建構式繼承.


是否能驗證繼承的物件呢 ?


實用技巧 :

可以避免在建構式建立時忘了 new 關鍵字導致根物件被汙染 .
看到以下範例有 SYM 與 KYMCO 這2個建構式函式,
但是在建立物件時候忘了使用 new,
SYM 函式裡面使用 instanceof 判斷 this 是否為自己的對象實例後將在一次使用 new 關鍵字,
KMYCO 函式可以看到忘記使用 new 關鍵字後 , this 判斷為 window 根物件導致全域汙染.



Apply 與 Call

簡單介紹這兩個 Javascript Method 用法.

apply

FuncName.apply(物件, [參數1, 參數2, ...]);

call

FuncName.call(物件, 參數1, 參數2, ...);

以下這兩篇文章已經提供了非常好的範例可以參考看看.

[javascript]Apply與Call用法說明
Javascript .apply()應用實例

總結
由於時間分配的關係以致於自己在寫文章進度緩慢.
在整理的時候能夠增進自身不足的部分.
也算是自學的一種.
若有引用連結或是轉載侵權的部分, 請留言通知或 Email 給我.

沒有留言: