前言

瀏覽器需要非常仔細的指令,才能了解我們希望它達成的工作,因此複雜的程式腳本是可以運行成千上萬行的指令,而程式設計師使用函式、方法與物件來組成程式碼。

圖片來源

 


 

什麼是函式?

函式可允許你將組合一系列的敘述句,以執行一項特定的工作,如果程式碼的不同程式區段經常被重複執行已完成相同的工作時,就是運用函式的好時機,將這些會經常執行的程式區段建立為可重複使用的函式,以避免重複撰寫相同的敘述。

var msg = '哈囉你好啊!';
function updateMessage() {
    var el = document.getElementById('message');
    el.textContent = msg;
}
updateMessage();

 


 

宣告函式

要建立一個函式,必須給它一個名稱,並在大括號內撰寫其工作任務所需的程式敘述,這樣的動作就叫函式宣告。

function sayHello() {
    document.write('Hello!');
}
  1. 宣告一個函式需使用 function 關鍵字。
  2. function 後面放置函式名稱,其後接著一對小括號。
  3. 執行工作的敘述句則放置於程式區段中( 大括號中 )。

 

宣告一個需要資訊的函式

有時函式需要一些特定資訊才能完成它的工作,在這樣的情況下,宣告函式時需再給予它參數,而在這類的函式內容中,參數的功能就有如變數一般。

// width 和 height 就是這個函式的參數
function getArea(width, height) {
    return width * height;
}

 


 

呼叫函式

完成函式宣告後,你就可以僅憑一行程式碼執行函式大括號內所有敘述句,這就是所謂的函式呼叫。

sayHello();

 

呼叫一個需要資訊的函式

當呼叫一個需要資訊的函式時,你必須在函式名稱後的括號中傳入須使用的值,這些數值就稱為引數,它們可以是數值或變數方式傳遞。

// 引數以數值方式傳遞
getArea(3, 5);

// 引數以變數方式傳遞
wallWidth = 3;
wallHeight = 5;
getArea(wallWidth, wallHeight);

 


 

自函式取得一個回傳值

有些函式在原始碼呼叫後會回傳資訊,例如下方範例: calculateArea() 函式會回傳四邊形的面積給原呼叫它的程式腳本,先建立名為 area 的變數儲存計算結果,並用關鍵字 return 回傳值。

function calculateArea(width, height) {
    var area = width * height;
    return area;
}
var wall = calculateArea(3, 5);

當 return 被執行後,解譯器便會跳出該函式並回到當初呼叫此函式的敘述句位置;若函式中的 return 後方還有其他敘述句則不執行。

 

自函式取得多個回傳值

函式可以使用陣列回傳多個值,例如下方範例: getSize() 函式會計算面積然後儲存在 area 中;然後把體積存在 volume ,而這兩個變數皆一同存放在 sizes 陣列裡。

function getSize(width, height, depth) {
    var area = width * height;
    vae volume = width * height * depth;
    var sizes = [area, volume];
    return sizes;
}
var areaOne = getSize(3, 2, 3)[0]; // 得 6
var volumeOne = getSize(3, 2, 3)[1]; // 得 18

 


 

函式類型

函式宣告

此類型會建立一個函式,讓它在程式腳本中可以被呼叫使用,因為必須在宣告時指定函式名稱,又稱為「 命名函式 」,解譯器在執行程式腳本中的每個區段前,都會先逐行尋找變數和函式的宣告位置,所以程式碼即使函式在宣告之前,它依然能夠被正確執行。

function area(width, height) {
    return width * height;
};
var size = area(3, 4);

函式運算式

當你將函式放置於解譯器期望運算發生之處,那麼此函式便會被視為一種運算式,此類型因為函式名稱通常被省略,所以又稱「 匿名函式 」,此方法的話,函式要等待解譯器執行到該行敘述時才執行,這表示解讀前你都無法呼叫此函式,同時該行敘述前的程式碼都有可能改變內部的運算狀況,

var area = function(width, height) {
    return width * height;
};
var size = area(3, 4);

 


 

立即執行函式運算式

IIFE ( 立即執行函式運算式 )發音類似「埃芙」,這類函式不具有名稱,而且只在解譯器解讀到時才執行,編寫方式可運用在多種不同的情況,一般來說多用以確保變數名稱不會發生互相衝突( 特別是當一個頁面中使用多個程式腳本 )。

出現在程式區塊大括號後的是最終結束括號( 綠色方框處 ),它的作用是告知解譯器需要立即執行此函式,而此處的群組運算子( 紅色方框處 )的作用是確保解譯器將此函式視為一運算式。

 

何時使用匿名函式與立即執行函式運算式

當函式在程式腳本中只會被執行一次,而不是多次在程式腳本中被呼叫執行時,則是適合使用匿名函式與立即執行函式運算式的時機,例如:

  • 作為呼叫函式時所需使用的引數( 計算函式所需要的值 )。
  • 指定給物件的特性值。
  • 當事件發生時,在事件處理器和偵測器中執行指定工作。
  • 為避免兩個程式腳本中有相同名稱的變數發生命名衝突。

 


 

變數有效範圍

宣告變數的位置會影響程式碼中變數的使用方式。

function getArea(width, height) {
    var area = width * height;
    return area;
}

var wallSize = getArea(3, 2);
document.write(wallSize);

區域變數

當變數使用關鍵字 var 在函式中宣告時,此變數就只能在函式中使用,稱為區域變數或函式階層變數,表示它在所宣告的函式之外就無法被存取使用,在上面的範例中, area 就是一個區域變數。

當函式開始執行時,解譯器會建立區域變數,一旦函式執行完畢,便會將這些區域變數移除,代表:

  • 若函式被執行兩次,則變數在兩次被執行時可能產生不同的值。
  • 兩個不同的函式中可以有相同名稱的變數且不會有命名上的衝突。

全域變數

若變數是在函式外宣告,那麼它就可在程式腳本的任何位置存取使用,稱為全域變數,在上面的範例中, wallSize 就是一個全域變數。

全域變數是儲存在電腦記憶體中,讓瀏覽器載入網頁內容的當下使用,所以會比區域變數佔用更多記憶體空間,且會增加命名衝突的風險,如果在宣告變數時未使用關鍵字 var 進行宣告,那麼解譯器會將它視為全域變數。

 


 

變數如何在記憶體中運作?

 

在程式碼中建立變數

每一個宣告的變數均會佔用記憶體空間,因此宣告越多變數,瀏覽器必須保留越多變數,你的程式碼就需要越多記憶體才可執行,會導致執行效率較差且網頁需要更長時間才能回應使用者。

var width = 15;
var height = 30;
var isWall = true;
var canPaint = true;

變數所參考的值會被儲存在記憶體中,相同的值可儲存在不同的變數裡,所以上方範例:牆壁的寬、高以變數 width 和 height 表示,分別儲存 15 和 30 兩個不同的值;但相同值的 true 也可以指定給 isWall 和 canPaint 兩個不同的變數。

 

命名衝突

如果一個 HTML 檔引入兩個 JavaScript 程式檔,且兩個程式檔中均有相同名稱的全域變數,就會造成錯誤,所以下方的範例:變數 msg 會產生命名衝突而 width 和 height 不會。

// 顯示方塊面積
function showPlotSize(){
    var width = 3;
    var height = 2;
    return 'Area: ' + (width * height);
}
var msg = showPlotSize();
// 顯示花園面積
function showGardenSize(){
    var width = 12;
    var height = 25;
    return width * height;
}
var msg = showGardenSize();

 


 

什麼是物件?

物件就是把一群變數和函式組合起來成為一個類似於真實世界的模型,在物件中的變數和函式會以新的名稱表示:變數稱為「特性」、函式稱為「方法」。

以下的物件代表一間旅館,它具有五項特性和一個方法;物件定義在大括號內,在此建立的物件則儲存於名稱為 hotel 的變數。

var hotel = {
    name: 'W hotel',
    rooms: 40,
    booked: 25,
    gym: true,
    roomType: ['twin', 'double', 'suite'],
    checkAvailability: function() {
        return this.rooms - this.booked;
    }
}

特性跟方法也都有它們自己的名稱與值,但在物件中,所定義的名稱叫作「鍵」,一個物件不可以有兩個鍵使用相同名稱。

鍵值
特性 name
rooms
booked
gym
roomType
字串
數值
數值
布林值
陣列
方法 checkAvailability 函式

 


 

建立物件

 

先建立物件,再加入特性與方法

實字標示法

實字標示法可以用大括號來建立空白物件。

var hotel = {}

hotel.name: 'W hotel';
hotel.rooms: 40;
hotel.booked: 25;
hotel.checkAvailability = function() {
    return this.rooms - this.booked;
}

建構子標示法

利用關鍵字 new 和 Object() ( 物件建構子 )可以建立一個空物件,然後後續再為物件加入特性和方法。

var hotel = new Object();
hotel.name: 'W hotel';
hotel.rooms: 40;
hotel.booked: 25;
hotel.checkAvailability = function() {
    return this.rooms - this.booked;
}

 

建立物件時,同時定義特性與方法

實字標示法

實字標示法是用以建立物件最簡易且常用的方式,鍵和鍵值以冒號分隔,各特性與方法間以逗號分隔( 但最後一個特性或方法的後方則不需要再加上逗號 )。

var hotel = {
    name: 'W hotel',
    rooms: 40,
    booked: 25,
    checkAvailability: function() {
        return this.rooms - this.booked;
    }
}

建構子標示法

有時候你會想要用多個物件來代表類似的事情,物件建構子能夠提供以函式的方式,作為建立物件的模板,首先,得先建立一個模板並包含物件所需的特性與方法,再使用建構子函式建立物件實體,關鍵字 new 後接著呼叫函式便可建立一個新物件,每個物件的特性值可透過引數的方式設定。

function Hotel(name, rooms, booked) {
    this.name = name;
    this.rooms = rooms;
    this.booked = booked;
    this.checkAvailabilityy = function() {
        return this.rooms - this.booked;
    };
}
var quayHotel = new Hotel('Quay', 40, 25);
var parkHotel = new Hotel('Park', 120, 77);

建構子函式的名稱經常以大寫開頭,原因是期望能提醒開發人員,當他們要使用此函式建立物件時記得加上關鍵字 new 才能夠正確建立。

 


 

存取物件和句點標示法

欲存取物件的特性和方法,可以用物件的名稱接著一個句點符號,後續再加上欲存取的特性或方法名稱,這就是句點標示法,句點符號也被稱為成員運算子。

var hotelName = hotel.name;
var hotelFree = hotel.checkAvailability();

存取物件的特性亦可使用方括號語法( 但不能用來存取方法 ),方括號語法存取物件特性的使用時機為:

  1. 特性的名稱為數值型態( 技術上可行,但使用上仍應避免 )。
  2. 以變數取代方括號中的特性名稱。
var hotelName = hotel['name'];

 


 

變更物件

要變更物件的特性值,可以使用句點標示或方括號方式進行,而若要刪除某項特性,則可用關鍵字 delete 。

// 變更物件特性值
hotel.name = 'Park';
hotel['name'] = 'Park';

// 刪除特性值
delete hotel.name;

// 將特性值清除重設,可用指定空字串
hotel.name = '';

 


 

關鍵字 this

關鍵字 this 經常使用在函式和物件之中,當函式被宣告後會影響 this 的內容,一般用來參考至一個物件,通常是使用 this 的函式所隸屬的物件。

 


 

陣列即為物件

陣列就是一種特殊物件,它可以儲存一系列的鍵/值配對( 就跟物件一樣 ),只是它每個值所對應的鍵就是陣列的索引值。

物件

特性
room1 420
room2 460
room3 230
room4 620
costs = {
    room1: 420,
    room2: 460,
    room3: 230,
    room4: 620
}

 

陣列

索引值
0 420
1 460
2 230
3 620
costs = [420, 460, 230, 620];

 


 

物件中的陣列與物件在陣列中

陣列和物件可以結合運用,以創造出複雜的資料結構,陣列可以儲存一系列的物件( 並記得儲存的順序性 );物件也可以儲存陣列( 作為物件的特性值 )。

物件中的陣列

特性
room1 items[420, 40, 10]
room2 items[260, 30, 20]
room3 items[110, 0, 0]
room4 items[620, 150, 100]
costs.room1.items[0];

 

陣列中的物件

索引值
0 {accom: 420, food: 40, phone: 10}
1 {accom: 360, food: 0, phone: 30}
2 {accom: 2, food: 20, phone: 0}
3 {accom: 550, food: 180, phone: 50}
costs[2].phone;

 


 

三種類型的內建物件

瀏覽器提供一系列的內建物件以表示一些與其相關的事項,例如:瀏覽器視窗、視窗內目前的頁面⋯⋯等,這些內建物件的作用就像是工作組,可以建立更具互動性的網站頁面。

 

瀏覽器物件模型

瀏覽器物件模型建立一個與瀏覽器頁籤或視窗有關的模型,下方的範例模型中,最頂層的是 window 物件,代表目前的瀏覽器和頁籤,它的子物件則代表其他的瀏覽器特徵和性質。

程式碼 描述
window.print(); window 物件的 print() 方法可使瀏覽器顯示列印對話框。
window.screen.width; screen 物件的 width 特性可取得裝置顯示器解析度的寬度。

 

文件物件模型

文件物件模型( DOM )建立一個與目前網頁相關的模型,最頂層是 document 物件,它代表一個頁面的整體,在它之下的子物件代表頁面中的其他元素項目。

程式碼 描述
document.getElementById('one'); document 物件的 getElementById() 方法可依據 id 屬性值取得元件。
document.lastModified; document 物件的 lastModified 特性可告訴你此頁面最後被更動的時間。

 

全域 JavaScript 物件

全域 JavaScript 物件並非是指所有全域物件,而是一組與 JavaScript 語言各個部分有關的物件。

程式碼 描述
hotel.toUpperCase(); String 物件的 toUpperCase() 方法可使變數的所有字母都轉成大寫。
Math.PI(); Math 物件的 PI 特性會回傳 pi 的數值。

 


 

瀏覽器物件模型: window 物件

window 物件代表的是目前的視窗或頁籤,它在瀏覽器物件模型的定義中是最頂層的物件,也包含了其他能夠提供瀏覽器相關資訊的物件,下表列出部分 window 物件的特性和方法:

特性 說明
window.innerHeight 視窗的高度( 不包含 chrome 瀏覽器/使用者操作介面部分 ),以像素為單位。
window.innerWidth 視窗的寬度( 不包含 chrome 瀏覽器/使用者操作介面部分 ),以像素為單位。
window.pageXOffset 網頁文件水平捲動的距離,以像素為單位。
window.pageYOffset 網頁文件垂直捲動的距離,以像素為單位。
window.screenX 滑鼠的 X 座標,相對於螢幕的左上角,以像素為單位。
window.screenY 滑鼠的 Y 座標,相對於螢幕的左上角,以像素為單位。
window.location window 物件目前的頁面 URL ( 或本機路徑 )。
window.document 參考至 document 物件,用以代表目前的頁面內容。
window.history 參考至 history 物件,用以擷取瀏覽器視窗或頁籤所包含的瀏覽紀錄資訊。
window.history.length history 物件中的瀏覽記錄筆數。
window.screen 參考至 screen 物件。
window.screen.width 使用 screen 物件並擷取它的 width 特性,以像素為單位。
window.screen.height 使用 screen 物件並擷取它的 height 特性,以像素為單位。

 

方法 說明
window.alert() 建立包含訊息文字的對話框( 使用者必須按下「 OK 」按鈕才可關閉 )。
window.open() 開啟新的瀏覽器視窗,並帶入指定 URL 位置作為參數值( 若瀏覽器有安裝禁止跳出視窗的軟體,此方法可能無法正確運作 )。
window.print() 通知瀏覽器開啟頁面列印對話框( 功能有如使用者按下瀏覽器的列印功能 )。

 


 

文件物件模型: document 物件

文件物件模型( DOM )的最頂層物件就是 document 物件,它代表的是載入至目前瀏覽視窗或頁籤中的頁面,下表列出部分 document 物件的特性和方法:

特性 說明
document.title 目前頁面的標題文字。
document.lastModified 目前頁面最後被更改的日期時間。
document.URL 目前頁面的 URL 位址。
document.domain 目前頁面的所屬網域。

 

方法 說明
document.write() 將文字寫入至文件。
document.getElementById() 取得具有符合所指定 id 屬性值的元件。
document.querySelectorAll() 取得所有符合 CSS 選擇器所設定參數條件的元件。
document.createElement() 建立新元件。
document.createTextNode() 建立新的文字節點。

 


 

全域物件: string 物件

無論何時需要處理一字串值時,都可以利用 string 物件的特性和方法,以下範例用一段儲存在變數中的片語“Home sweet home”說明:

var saying = 'Home sweet home ';

字串中的每一個字元都自動被指定一個順序數值,稱為索引值,一般來說,索引值都是從零起始的。

特性 說明 範例 結果
length 取得字串中的字元數量。 saying.length;
16

 

方法 說明 範例 結果
toUpperCase() 將字串轉換為大寫字元。 saying.toUpperCase();
'HOME SWEET HOME '
toLowerCase() 將字串轉換為小寫字元。 saying.toLowerCase();
'home sweet home '
charAt() 傳遞索引值作為參數,並取得位於該索引值位置的字元。 saying.charAt(12);
'o'
indexOf() 取得一個字元或字元集合第一次在字串中出現的位置索引值。 saying.indexOf('ee');
7
lastIndexOf() 取得一個字元或字元集合最後一次在字串中出現的位置索引值 saying.lastIndexOf('e');
14
substring() 取得兩個索引值之間的字元,所包含的字元自第一個索引值開始,至第二個索引值的前一個字元在內。 saying.substring(8,14);
'et hom'
split() 指定一字元作為字串分割字元,當該字元於字串中出現時,就將字串進行切割,並將分割後的結果儲存到陣列中。 saying.split(' ');
['home', 'sweet', 'home', '']
trim() 自字串的開頭和尾端處移除空白字元。 saying.trim();
'Home sweet home'
replace() 有如搜尋取代功能,先指定一搜尋值與取代值,以搜尋值比對出目標字元後,再以取代值替換該目標字元( 預設只會取代第一個搜尋到的目標字元 )。 saying.replace('me','w');
'How sweet home '

 

全域物件: number 物件

無論何時當你擁有一數值資料,都可以直接使用 number 物件的特性和方法。

方法 說法
isNaN() 檢查值是否為數值。
toFixed() 四捨五入至小數點後指定位數( 回傳值為字串型別 )。
toPrecision() 四捨五入至指定的整數位數( 回傳值為字串型別 )。
toExponential() 以指數表示法顯示數值( 回傳值為字串型別 )。

常用名詞:

  • 整數( integer )是指一個數值,不含小數部位。
  • 實數( real number )是指包含整數與小數的數值。
  • 浮點數( floating point number )是指有小數部位的實數,所謂浮點是指小數點。
  • 科學記號表示法( scientific notation )可方便地以小數點的型式表示極大或極小的數值,例如: 3,750,000,000 可以表示為 3.75 x 10⁹ 或 3.75e + 12 。

 

全域物件: math 物件

math 物件定義的特性和方法可對應至數學運算的常數與函式。

特性 說明
Math.PI 回傳 pi 常數值( 趨近於 3.14159265359 )。

 

方法 說明
Math.round() 四捨五入運算。
Math.sqrt(n) 開根號運算,例如: Math.sqrt(9) 會取得回傳值 3 。
Math.ceil() 向上取整數( 取得大於或等於指定數值的整數 )。
Math.floor() 向下取整數( 取得小於或等於指定數值的整數 )。
Math.random() 隨機產生 0 ( 包含 )與 1 ( 不包含 )之間的數值。

產生介於 1 至 10 之間的整數:

var randomNum = Math.floor((Math.ranfom() * 10) + 1);

 


 

全域物件: date 物件( 和 time )

為處理日期資料,必須建立 date 物件實體,你可以指定它所代表的時間和日期,當你建立 date 物件時,預設會儲存當天的日期和當下時間,如果想儲存其他日期及時間須另外指定。

var today = new Date();

在 JavaScript 中日期被以數值的方式儲存,且為一個自西元 1970 年 1 月 1 日午夜起算,以毫秒為單位的數值,你可以用以下的格式設定日期、時間,也可以使用下方表格所列的方法:

var dob = new Date(1996, 11, 26, 15, 45, 55);
var dob = new Date('Dec 26, 1996 15:45:55');
var dob = new Date(1996, 11, 26);

注意,當前日期/時間是以本機時鐘為準,如果使用者與你的時區不同,那麼他們的時間有可能就會不同,且如果本機時鐘不準確或錯誤,那 date 物件就會儲存錯誤的日期時間。

方法 說明
getDate() 、 setDate() 回傳/設定月份日期( 1-31 )。
getDay() 回傳當週的日次( 0-6 )。
getFullYear() 、 setFullYear() 回傳/設定年份( 4 )。
getHours() 、 setHours() 回傳/設定小時( 0-23 )。
getMilliseconds() 、 setMilliseconds() 回傳/設定毫秒( 0-999 )。
getMinutes() 、 setMinutes() 回傳/設定分鐘( 0-59 )。
getMonth() 、 setMonth() 回傳/設定月份( 0-11 )。
getSeconds() 、 setSeconds() 回傳/設定秒數( 0-59 )。
getTime() 、 setTime() 回傳/設定從西元 1970 年 1 月 1 日 0 點 0 分 0 秒至物件時間值的毫秒數,負數則表示在此之前的日期。
getTimezoneOffset() 回傳本機時間與 UTC 時間之間的差異分鐘數。
toDateString() 回傳具可讀性的日期字串,會以「 Wed Apr 16 1975. 」這種格式顯示日期,如果要改變格式再以上述物件方法修改。
toTimeString() 回傳具可讀性的時間字串,訪客所在位置可能會影響時區和語言,程式設計師定義語系( locale )來談論這類與位置地點相關的資訊。
toString() 回傳日期時間的字串。

著作權( copyright )文字使用當前年份:

var today = new Date();
var year = today getFullYear();

var el = document.getElementById('copyright');
el.innerHtml = '<p>Copyright &copy;' + year + '</p>';

 


 

參考資料

JavaScript & jQuery 網站互動設計程式進化之道( Jon Duckett 著、謝銘倫 譯 )


#js #JS註冊組 #javascript #JavaScript & JQuery #網站互動設計程式進化之道 #函式 #function #return #IIFE #var #new #Object() #Delete #this #陣列 #window #print() #screen #width #height #document #getElementById() #lastModified #string #toUpperCase() #math #PI() #innerHeight #innerWidth #pageXOffset #pageYOffset #screenX #screenY #location #history #length #alert() #open() #title #url #Domain #write() #querySelectorAll() #createElement() #createTextNode() #toLowerCase() #charAt() #indexOf() #lastIndexOf() #substring() #split() #trim() #replace() #number #isNaN() #toFixed() #toPrecision() #toExponential() #整數 #實數 #浮點數 #科學記號表示法 #round() #sqrt() #ceil() #floor() #random() #Date #Time #getDate() #setDate() #getDay() #getFullYear() #setFullYear() #getHours() #setHours() #getMilliseconds() #setMilliseconds() #getMinutes() #setMinutes() #getMonth() #setMonth() #getSeconds() #setSeconds() #getTime() #setTime() #getTimezoneOffset() #toDateString() #toTimeString() #toString()







Related Posts

JavaScript 設計模式:單體模式 ( Singleton )

JavaScript 設計模式:單體模式 ( Singleton )

Day07:V8 bytecode 系列文總結

Day07:V8 bytecode 系列文總結

Leetcode 刷題 pattern - Two Heaps

Leetcode 刷題 pattern - Two Heaps


Comments