陳述式(Statmene):執行JS的指令的語句,不會回傳結果。
例如:
// 流程控制
if else
break
// 宣告
var
const
let
// 指定含式類別
function
// 迭代
for
表達式(Expression):又稱運算式,透過上下的語句與符號運算並回傳結果/取得一個值。
例如:
// 雖然這個運算是沒有指定變數來儲存值。
123 + 13;
// 賦值是一種表達式
string = 'string'
函式陳述式:直接使用function宣告的函式,又稱具名函式。
例如:
function myFunction() {
}
含式表達式:宣告一個變數並賦值函數。
例如:
// 後面沒有名稱的是匿名含式
var callFunction = function(){
}
先看個範例
function callJack() {
return
'Jack';
}
console.log(callJack()) // undefined
在修改為
function callJack() {
retrun 'Jack';
}
console.log(callJack()) // 'Jack'
會有開頭那個範例的問題是因為,ASI為自動把語句的結尾加上;
所以開頭的範例實際上是
function callJack() {
// rerurn後面直接上加上分號,所以沒有return任何東西
return;
'Jack';
}
console.log(callJack()) // undefined
立即函式間的;
(function(){
console.log('立刻執行')
}())
(function(){
console.log('立刻執行2')
}())
以上程式碼會報錯,ASI並不會自動加入;
必須加入分號才會順利執行
(function(){
console.log('立刻執行')
}()); // 這裡加分號
(function(){
console.log('立刻執行2')
}())
// '立刻執行'
// '立刻執行2'
容易出錯的範例
let a = 1
(function(){
console.log(a)
})()
//1 is not a function
會出現上面的錯誤是因為,在新的一行開頭為
( [ / + - * % , .
時上一行式不會自動加入分號的。
也就是說實際執行是
let a = 1(function(){console.log(a)})()
修改方式為以下
let a = 1;
(function(){
console.log(a)
})() // 1
JavaScript在執行的時候才會賦予確認的型別。
例如:
let string = '文字'
console.log(typeof string) // "string"
string = 1
console.log(typeof string) // "number"
可以觀察到變數string賦值1的時候型別就從字串轉成數字。
上述的範例就是顯性轉換的例子
let num = 123
console.log(num, typeof num) // 123 "number"
num = num + ''
console.log(num, typeof num) // '123' "string"
num = num / 1
console.log(num, typeof num) // 123 "number"
從上面的範例看到num這個變數的型別經過運算後被改變,這就是隱性的轉換。
字串(string)
數字(number)
布林(boolean)
未定義(undefined)
空(null)
Bigint
Symbol
其中只有null與undefined沒有包裹物件。
包裹物件就是讓原始型別有一些方法能夠使用,例如大小寫轉換。
let a = 'a'
let A = new String(a)
console.log(A) // String {'a'}
點擊String {'a'}後再點擊Prototype就可以查到,包裹物件的方法
不過包裹物件的型別是物件,是建構式,一般宣告普通型別時不會這樣子用。
delete
// 用來刪除物件、物件屬性、或陣列中指定的index
typeof
// 用來回傳代表運算元類型
let condiction = true
console.log(condiction? 'go':'stop') // 'go'
//?前為判斷式,結果為true的話就會執行:左邊,如果是false則執行:右邊
優先性(Precedence):運算子間優先度的順序。
相依性(Associativity):決定運算方向。
可以參考連結中的table,其中數字越大代表優先度越高,如果優先度相同則依照相依性的方向執行。
以下為等號的相依性為例子
等號的相依性由右至左
const obj = {}
Object.defineProperty(obj, 'a',{
value:1,
writable:false
})
obj.a = 5
// 現在obj.a 無法被寫入
console.log(obj.a) // 1
Object.defineProperty(obj, 'b',{
value:3,
writable:false
})
let a = 2
a = obj.b = obj.a = 100
// obj.a = 100 為表達式,會回傳100,但是obj.a在上面設定不可寫入,所以沒辦法被賦值,obj.b也相同,最後a被賦值是obj.a = 100的回傳值。
console.log(a) // 100
console.log('obj.a', obj.a) // 1
console.log('obj.b', obj.b) // 3
a = obj.b = obj.a = 100
如果照步驟拆開來看就是
obj.a = 100 為表達式回傳100,但是obj.a不會被寫入回傳值所以
obj.b = 100 為表達式回傳100,但是obj.b不會被寫入回傳值所以
a = 100 為表達式回傳100,a被賦值回傳的數值。
嚴格相等會先判斷資料的型別,再判斷資料的值是否相同。
例如:
console.log(1 === 1) // true
console.log('2' === '2') // true
console.log(1 === '1') // false
不過也有例外的時候
例如:
console.log(NaN === NaN) // false
console.log(+0 === -0) // true
console.log(undefined === null) // false
console.log('1' == 1) // true
console.log(true == 1) // true
console.log(true == '1') // true
console.log(true == 'true') //false
// 因為true會被轉為1, 'true'則是無法轉為數字,結果為NaN,所以結果為false
以上範例會將布林與字串轉為數字後做比較。
再寬鬆相等時 true '1'會轉換為1,false與'0'則轉換為0
再來看看比較特別的範例
console.log('1' == !0) // true
'1'轉換為數字1
!0 轉換為 true,再轉換為1
console.log(!0) // true
console.log(Number(null)) // 0
console.log(Number(undefined)) // NaN
雖然null使用Number轉型是轉型為0但是,再寬鬆相等的情況下不轉型。
console.log(null == 0) // false
console.log(undefined == 0) // false
再來是與嚴格相等不同的是再寬鬆相等的情況下null等於undefined
console.log(undefined == null) // true
物件與非物件比較時,使用包裹物件做轉換。
console.log(1 == [1]) // true
console.log('1' == [1]) // true
console.log(true == [1]) // true
上面範例中的[1]會使用包裹物件轉型為數字後比較。
console.log('a' == ['a']) // true
與數字的範例相同,也是同樣用包裹物件轉型為字串後比較。
物件與物件間的比較
console.log([] == []) // false
console.log({} == {}) // false
會出現false的原因是物件比較的不是值,是參考位置,也就是不同的物件所存放的記憶體空間不同。
const a = {}
const b = a
console.log(a === b) // true
console.log(a == b) // true
因為a 與 b的參考位置相同所以比較結果為true。
與自動轉型不同
if(5) {
console.log('我執行了')
}
// "我執行了"
console.log(5 == true) // false
上面的例子中if條件內的5是真值,與寬鬆比較把true轉為1不同。
&&、||、!
用來驗證兩個值是否為真值
(Expression1 && Expression2)
Expression1為falsy則回傳Expression1,Expression1為truthy則回傳Expression2,如果都是boolean則是兩者都是true才會回傳true,否則回傳false。
(Expression1 || Expression2)
Expression1為thruthy,回傳Expression1,Expression1為falsey回傳Expression2,如果都是boolean則是其中之一只要是true季就回傳true,兩者都是false才會回傳false。
truthy轉為falsy,falsy轉為truthy。
特別的例子
let money = 500
function saveMoney(data) {
data = data || 100
console.log(`現在有${money + data}`)
}
saveMoney() // "現在有600"
但是以上的範例如果saveMoney(0)就會出現NaN
需要使用三原運算做修改,
let money = 500
function saveMoney(data) {
(data===undefined || data===0)? data=0 : data
console.log(`現在有${money + data}`)
}
saveMoney(0) // "現在有600"
也可以使用if條件式,兩者意思相同。
let money = 500
function saveMoney(data) {
if(data===undefined || data===0){
data = 0
}
console.log(`現在有${money + data}`)
}
saveMoney(0) // "現在有600"
還有在QA工作有兩個主管,一位是經理、另一位是副經理,兩者都不是好主管,經理呢舌燦蓮花,把黑的說成白的,畢竟傳產尿性就是這樣你知道他在講幹話,你反駁他也沒用,畢竟他職位比你大,另一位副經理遇到事情就是推、拖、閃,一心只想完成他的學業而以,還有他的法規顧問夢,不知道是風險管理這個職位的流動率太高還是真的太為下屬著想,經理一直鼓勵我快買房,買房當然不錯啊但有沒有想過我一個月實領不到3萬,寬限期過之後房貸一個月要還3萬5,做一個月沒辦法吃飽就算了還倒貼,更瞎的是一直鼓勵去借錢玩當沖,說當沖零成本之類的幹話,想把人綁下來當長工有沒有考慮過更不缺德的方法呢?例如加薪。