JavaScript - Basic

基礎概念

JavaScript 是一門基於原型、函式先行的程式語言,支援物件導向。簡言之,是一種可在網站裡加入動態效果的程式語言,例如更改樣式、展示動畫等

概論

一般來說,完整的 JavaScript 包括以下幾個部分:

  • ECMAScript,描述了該語言的語法和基本物件
  • 文件物件模型(DOM),描述處理網頁內容的方法和介面
  • 瀏覽器物件模型(BOM),描述與瀏覽器進行互動的方法和介面

JavaScript 的基本特點如下:

  • 是一種解釋性程式語言(代碼不進行預編譯)。
  • 主要用來向 HTML 頁面添加互動行為。
  • 可以直接嵌入 HTML 頁面,但寫成單獨的 js 檔案有利於結構和行為的分離。

JavaScript 常用來完成以下任務:

  • 嵌入動態文字於 HTML 頁面
  • 對瀏覽器事件作出回應
  • 讀寫 HTML 元素
  • 在資料被提交到伺服器之前驗證資料
  • 檢測訪客的瀏覽器資訊
  • 控制 cookies,包括建立和修改等

動態型別

JavaScript 是一種「弱型別」的程式語言,在變數的資料型別與其他的程式語言相當不同,它是以「動態型別」(Dynamic Typing) 處理資料型別。

程式語言會依照語言的型別系統分成「強型別語言」和「弱型別語言」。強型別是指「程式定義的變數型別等於變數在執行的時候的型別」,這類語言的變數在宣告的時候,必須指定一種資料型別給它。弱型別正好相反,因此具有語法簡潔的優點。JavaScript 的變數在宣告時無需指定型別。

JavaScript 程式在運作時,型別會自動轉換。這也代表你可以以不同的型別使用同一個變數。因為型別的資訊只在「值」或「物件」本身,變數只是用來取得值或物件的參考。

資料型別

基本型別 (Primitive)

  • string 字串
  • number 數字
  • boolean 布林值 (true/false)
  • null 只有一個 null 值
  • undefined 只有一個 undefined 值

物件型別 (Object)

  • object:所有基本型別以外的值都是物件。在真實世界中,以一台汽車為例,我們可以用時速、顏色、油耗描述一台車子的屬性,這些屬性各自具備不同的值。同樣的,在 JavaScript 當中,每個物件也是可以用都是一特性 (properties)、事件 (event)、方法(method) 來描述的實體 (instance)的特性。一個物件的特性是鍵 (key) 與值 (value) 的配對。
1
object=            {key:value}

以下是一個物件的例子

1
2
3
4
5
6
7
8
9
var car = {
brand: ford,
color: red,
secondHand: true,
bwh: {
strength: 34,
fuel: desel,
},
};

brand,color 是 key; ford,red 是 value。物件的屬性是可以新增與刪除的。但是原始型別沒有屬性。是一個值,沒有屬性,且是不可變異(immutable)。必要時,JavaScript 引擎會將原始別強制轉型為對應的物件型別(除了 null & undefined)。

1
2
3
var foo = 42; // foo 目前是數字
var foo = "bar"; // foo 目前是字串
var foo = true; // foo 目前是布林值

Truthy and Falsy

在 JavaScript 裡面,所有的值都有真(truthy)和假(falsy)之分。可用來檢視頁面上的元件是否存在。

1
2
3
4
5
6
7
//falsy "", '',``,0,-0,NaN,false,,null,undefined
const txt = "n";
if (txt) {
console.log("the value is truthy");
} else {
console.log("the value is falsy");
}

基本功能

運算子

一元運算子

算數運算子除了用來作「兩個數值」的四則運算、取餘數得作用之外,也有另外一種運算子只需要單個數值就可以完成運算,稱為一元運算子。正號 + 與負號 - 分別用來表示數字的正數與負數狀態

1
2
var a = +10;
console.log(a); //10
  • ++ 遞增、--遞減

比較運算子

比較運算子有兩個運算元,是用來比較運算子兩側的數值,比較後得到 true 或 false

三元運算子

條件 (三元) 運算子 是 JavaScript 唯一用到三個運算元的運算子

1
condition ? exprIfTrue : exprIfFalse

也就是條件?如果條件成立回傳值:如果條件失敗回傳值

陣列

Array 是一種特別類型的變數,在 JavaScript 裡,它用來儲存值,但不只儲存單一個值,而是一系列的值。當需要運用一系列或值跟值之間有關連性的狀況時,應該要考慮用陣列。以下是幾個常見的例子與陣列運用方式:

建立陣列

1
var colors = ['white','red','green'];

運用 index 存取或變更陣列中的指定項目

1
2
var first = index[0];//white
colors[2]= purple

push():在陣列最末端加入 item

1
var newNum = colors.push(3);// var colors = ['white','red','green',3];

pop():移除陣列最後一個項目

1
var last=colors.pop();//var colors = ['white','red','green'];

shift():移除 array 最前面一個 item

1
var first = colors.shift();//var colors = ['red','green'];

unshift():從 array 最前面加入 item

1
var fruite = colors.unshift('apple');//var colors = ['apple','red','green'];

indexOf():會回傳給定元素於陣列中第一個被找到之索引,若不存在於陣列中則回傳 -1。

1
2
3
4
5
6
7
8
9
10
11
const beasts = ['ant', 'bison', 'camel', 'duck', 'bison'];

console.log(beasts.indexOf('bison'));
// expected output: 1

// start from index 2
console.log(beasts.indexOf('bison', 2));
// expected output: 4

console.log(beasts.indexOf('giraffe'));
// expected output: -1

slice():回傳一個新陣列物件,為原陣列選擇之 begin 至 end(不含 end)部分的淺拷貝(shallow copy)。而原本的陣列將不會被修改。

1
2
3
4
5
6
7
8
9
10
11
12
var fruits = ['banana','orange','lemon','grape'];
var citrus = fruits.slice(1,3);
// ['orange','lemon']

var nums = [1,2,3];
var otherNum = num.slice();
// [1,2,3]


var nums = [1,2,3,'a','b',4,5,6];
var letters = nums.slice(3,5);
//['a','b']

splice(pos, index):移除從 pos 起的幾個項目(注意是用 index 計算)

1
var removeItem = arr.splice(0, 2); // colors = ['green'];

forEach():會將陣列內的每個元素,皆傳入並執行給定的函式一次。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
var arr1 = [a, b, c];
arr1.forEach(function(element){
console.log(element);
})
// 印出最大值
var nums = [1, 2, 3, 4, 5];
let biggest = 1;

nums.forEach(function (num) {
if (biggest < num) {
biggest = num;
}
console.log(biggest);
})

// 加總
var nums = [1, 2, 3, 4, 5];
let sum = 0;
var nums = [1, 2, 3, 4, 5];
let sum = 0;

//找相等
var arr = [1, 2, 3, 4, 5];

function isUniform() {
var firstValue = arr[0];
var bool = true;
arr.forEach(function (check) {
if (firstValue !== check) {
bool = false;
}
});
return bool;
}
isUniform();
//倒轉
var arr = [1, 2, 3, 4, 5]
arr.slice().reverse().forEach(function (x) {
console.log(x);
})

Function

函式是為了解答某個問題或執行一項指定的工作,而組合而成的敘述句集合。簡言之函式把某項工作的執行步驟先儲存起來,當有需要的時候,再要求韓式去執行這些步驟。函式也是物件的一種,在 JavaScript 裡,函式是「一級物件」(first class object)。一級物件指的是可以將韓式存放在變數、物件、陣列之中

函式的組成包括:

  • 函式的名稱。
  • 包圍在括號()中,並由逗號區隔的一個函式參數列表。
  • 包圍在大括號{}中,用於定義函式功能的一些 JavaScript 語句。

函式定義

  1. 函式宣告式
    「函式宣告」應該是最常見的用法,必須在宣告時指定函式名稱,也稱為「命名函式」
1
2
3
function getArea(width, height) {
//do something
}
  1. 函式表達式、函式運算式

透過 變數名稱 = function([參數]){ … }; 的方式,將一個函式透過 = 指定給某個變數。因為函式實際上它仍屬於 Object 的類型,是一種可以被呼叫 (be invoked) 的特殊物件 (值),因此可以透過變數存入。這類沒有名稱的函式稱為「匿名函式」

1
2
3
var area = function (width, height) {
//do something
};
  1. 透過 new Function 關鍵字建立函式

使用 Function (注意 F 大寫) 這個關鍵字來建立函式物件。 使用時將參數與函式的內容依序傳入 Function,就可以建立一個函式物件了

1
var square = new Function("number", "return number * number");

參考資料
https://ithelp.ithome.com.tw/articles/10191549
https://orow.github.io/2019/02/28/basic-javascript/

提昇 (Hoisting)

函式陳述式(Function Declaration)與函式表達式(Function Expressions)的差異。
函式宣告建立的函數,會被提升(hoisting)到該作用域(scope)最頂端,讓整個作用域都可以呼叫它。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
declared();
// 輸出 declared
// 函式陳述式 function declaration
function declared() {
console.log("declared");
}

expressed();
// TypeError: undefined is not a function
// 函式表達式 function expressions
var expressed = function () {
console.log("expressed");
};
expressed();
// 輸出 expressed

立即執行函式 (IIFE)

此類函式一般作為一種程式碼包裝紙的保護概念,讓匿名函式中宣告變數可以有效的跟其他程式腳本裡相同名稱的變數保護隔離,避免相互干擾。因此立即執行函式沒有名稱。

1
2
3
4
5
6
var area = (function (place) {
var width = 3;
var height = 2;
console.log("This " + place + " totla is " + width * height);
// consolo.log會印出 This undefined totla is 6
})();

作用域 (Scope)

變數宣告的位置會影響程式碼裡變數的使用方式,如果把變數宣告在函式裡,這個變數就只能在這個函式中使用,這就是變數有效範圍 (scope)。在 JavaScript 當中,以是否在函數當中宣告來區分「全域變數」和「區域變數」。

  • 例 1:
    這裡得出來的會是 150 跟 1,這是因為函式 doSomething()裡面再次定義了變數 x ,而且變數有效範圍的最小單位是 function,所以在函式區塊內透過 var 定義的 x 實際上只屬於這個函式。所以函式以外的 x 跟函式內的 x 是兩個不同的變數。
1
2
3
4
5
6
7
var x = 1;
var doSomething = function (y) {
var x = 100;
return x + y;
};
console.log(doSomething(50));
console.log(x);
  • 例 2:
    如果 function 內部沒有宣告 var x,就會一層一層向外找,直到全域變數為止。如果都沒有就會報錯: x is not defined。但要注意 function 可以讀取外層已宣告的變數,但外層拿不到裡面宣告的變數。
1
2
3
4
5
var x = 1;
var doSomething = function (y) {
return x + y;
};
console.log(doSomething(50)); //51
  • 例 3:
    兩個 function 都有 x,但不同區域的同命變數實際上是不同的。即使 x 被宣告 3 次,但彼此之間沒有關係,都是獨立的變數。
1
2
3
4
5
6
7
8
9
10
11
12
var x = "1";
function getValue1() {
var x = "100";
return x;
}
function getValue2() {
var x = "200";
return x;
}
console.log(getValue1()); //區域1
console.log(getValue2()); //區域2
console.log(x); //全域
  • 例 4:
    如果把 fuction 裡面的宣告關鍵字 var 拿掉,會得出 150 及 100 ,因為雖然 function 是切分變數有效範圍的單位,但前提是必須在 fuction 內部再次用 var 宣告變數,不然 JavaScript 會往外層去找同名變數,直到最外層的全域物件。所以這個裡子裡因為沒有在 function 裡重新宣告 x ,所以 x = 100 跑去變更更外層的同名變數。導致第二個印出的 x 的值變成 100 (後來 ES6 用 let 跟 const 分別定義 「變數」與「常數」,來改善 var 有時候會污染全域的問題)。
1
2
3
4
5
6
7
var x = 1;
var doSomething = function (y) {
x = 100;
return x + y;
};
console.log(doSomething(50)); //150
console.log(x); //100

Powered by Hexo and Hexo-theme-hiker

Copyright © 2013 - 2020 CYC'S BLOG All Rights Reserved.

UV : | PV :