1. JavaScript的變量
1.1 變量定義
一個 JavaScript 標識符必須以字母、下劃線(_)或者美元符號($)開頭;後續的字符也可以是數字(0-9),因爲 JavaScript 語言是區分大小寫的,所以字母可以是從“A”到“Z”的大寫字母和從“a”到“z”的小寫字母。
a = 100
var b = 200 // 變量定義時初始化
let c = 'abc'
console.log(d) // 不會報錯,直接打印undefined
var d // 變量申明,可以申明提升
let f // 變量申明,ES6新增的關鍵字
d = 500 // 變量賦值,相當於定義全局變量
const g = 600 // 常量定義,常量必須申明時賦值,之後不能再改變
// 明天會更好
var a
let b
console.log(1, a, b)
// 1 undefined undefined
a = 100
b = 'a string'
console.log(2, a, b)
// 2 100 'a string'
// 常量必須聲明時賦值,之後不能在改
const c = 100
console.log(c)
// c = 200 // 會報錯,常量不允許修改
var y // 只是聲明,y值爲undefined
var x = 5 // 規範的聲明並初始化,聲明全局變量或局部變量
z = 6
/* 不規範的初始化,不推薦,在嚴格模式下回產生異常,在賦值之前不能引用,
因爲它沒有申明。一旦這樣賦值,就是全局作用域。
*/
function hello()
{
var m // 只是申明,m爲undefined,作用域在函數中
m = 100 // m爲局部變量
}
// console.log(m) // 未申明變量m,異常
var申明一個變量,會把變量提升到當前全局或函數作用域。let申明一個語句塊作用域中的局部變量,const申明一個常量。JS中的變量申明和初始化時可以分開的。如果明確知道一個標識符定義後不再修改,應該儘量申明成const常量,減少被 修改的風險,減少bug。
1.2 變量提升
JavaScript變量的另一個不同尋常的地方是,你可以先使用變量稍後再聲明變量而不會引發異常。這一概念稱爲變量提升;Javascript變量感覺上是被提升或 移到了函數或語句的最前面,但是提升後的變量將返回undefined值。因此在使用或引用某個變量之後進行申明和初始化操作,這個被提升的變量將返回undefined值。
console.log(x === undefined) //true
var x = 5
var myvar = 'my value'
function a(){
console.log(myvar) // undefined
var myvar = 'local value'
}
a()
// 上面的函數等價於下面的函數
function a(){
var myvar
console.log(myvar)
myvar = 'local value'
}
a()
函數提升:對於函數來說,只有函數申明會被提升到頂部,而函數表達式不會提升。
foo() // bar
function foo(){
console.log('bar')
}
baz() // 類型錯誤:baz不是一個函數,只是一個函數表達式
var baz = function(){
console.log('bar2')
}
2. 數據類型
ES是動態語言,弱類型語言。雖然先申明瞭變量,但是變量可以重新賦值任何類型。
2.1 數據類型測試
// 類型轉換
// 弱類型語言
console.log("============string===============")
console.log(a = 3 + 'sun', typeof(a))
console.log(a = null + 'sun', typeof(a))
console.log(a = undefined + 'sun', typeof(a))
console.log(a = true + 'sun', typeof(a))
/*
============string===============
3sun string
nullsun string
undefinedsun string
truesun string
*/
// number
console.log('==========number===============')
console.log(a = null + 8, typeof(a))
console.log(a = undefined + 8, typeof(a)) // undefined沒法轉換成一個對應的數字
console.log(a = true + 8, typeof(a))
console.log(a = false + 8, typeof(a))
/*
==========number===============
8 'number'
NaN 'number' // NaN not a number
9 'number'
8 'number'
*/
// boolean
console.log('===========bool===========')
console.log(a = null + true, typeof(a))
console.log(a = null + false, typeof(a))
console.log(a = undefined + true, typeof(a)) // undefined無法轉換成一個對應的數字
console.log(a = undefined + false, typeof(a))
console.log(a = null & true, typeof(a))
console.log(a = undefined & true, typeof(a)) // 0
// 短路
console.log(a = null && true, typeof(a)) // 邏輯運算符null直接就是false短路
console.log(a = false && null, typeof(a)) // 邏輯運算符,false短路直接返回false
console.log(a = false && 'sun', typeof(a))
console.log(a = true && 'sun', typeof(a))
console.log(a = true && '', typeof(a)) // 結果a爲空字符串
console.log(a = {} && 'sun', typeof(a))
console.log(a = [] && 'sun', typeof(a))
// 注意[], {}與python中不同,在JS中,對象等價於true
/*
===========bool===========
1 'number'
0 'number'
NaN 'number'
NaN 'number'
0 'number'
0 'number'
null 'object'
false 'boolean'
false 'boolean'
sun string
string
sun string
sun string
*/
// null
console.log('=========null============')
console.log(a = null + undefined, typeof(a))
// NaN 'number'
弱類型,不需要強制類型轉換,會隱式類型轉換。NaN,即not a number,轉換數字失敗,它和任何值都不等,和自己也不等,只能使用Number.isNaN(NaN).
總結:遇到字符串,加號就是拼接字符串,所有非字符串隱式轉換爲字符串,如果沒有字符串,加號把其他所有類型都當數字處理,非數字類型隱式轉換成數字。undefined特殊,因爲它沒有定義值,所以轉換成數字失敗得到一個特殊值NaN。如果運算符是邏輯運算符,短路符,返回就是短路時的類型。沒有隱式轉換。除非你十分明確確,否則不要依賴隱式轉換,寫代碼的時候,往往爲了程序的健壯,請顯示轉換。
2.2 字符串
將一個值使用單引號或者雙引號引用起來就是字符串。ES6提供了反引號定義一個字符串,就可以支持多行,還支持插值。
let a = 'abc'
let b = "123"
let c = `line
line2
line3
` // 支持多行
console.log(c)
/*
line
line2
line3
*/
// 字符串插值,要求在反引號字符串中,python3.6支持
let name = "tom", age = 19
console.log(`Hi, my name is ${name}. I am ${age}`)
// Hi, my name is tom. I am 19
2.3 轉義字符
2.4 字符串操作方法
字符串方法很多,跟python類似。
let school = 'magedu'
console.log(school.charAt(2)) // g,字符串下標從0開始
console.log(school[2]) // g
console.log(school.toLocaleUpperCase()) // MAGEDU
console.log(school.concat('.com')) // 連接
console.log(school.slice(3)) //切片,支持負索引
console.log(school.slice(3, 5)) // ed 前包後不包,跟python切片是一樣的
console.log(school.slice(-2, -1)) // d
console.log(school.slice(-3)) // 後三個
let url = "www.magedu.com"
console.log(url.split('.')) // 結果是列表,跟python是一樣的
console.log(url.substr(4, 6)) // 返回子串從何處開始,取多長,注意下從0開始
// magedu
console.log(url.substring(7, 10)) // 返回子串從何處開始,到什麼爲止
// 注意是前包後不包
let s = 'magedu.edu'
console.log(s.indexOf('ed')) // 3
console.log(s.indexOf('ed', 4)) // 7
console.log(s.replace('.edu', '.com'))
// magedu.com
s = ' \tmag edu \r\n'
console.log(s.trim()) // 去除兩端的空白字符,trimleft、trimright是非標函數,少用
// mag edu