! 对待JS: 取其精华,去其糟粕
🌟 推荐书籍
- 适合入门《网道 JavaScript 教程》
- 适合进阶《你不知道的 JavaScript(上卷)》
「一」 表达式和语句
1. 表达式
- 1+2 表达式的值为3
- add(1,2) 表达式的值为函数的返回值
- console.log 表达式的值为函数本身(因为没加括号)
- console.log(3) 表达式的值为多少?
- 表达式的值为函数的返回值 ,log函数并没有设定返回值,JS默认返回 undefined,∴ console.log(3) 表达式的值为 undefined
- 3只是打印出的东西 ⚠️注意: 值 和 返回值 是不一样的,只有函数有返回值
2. 语句
var a = 1
是一个语句
2.1 变量声明 var / let / const
三种声明方式
var a=1 //var 是过时的、不好用的方式
let a=1 //let 是新的,更合理的方式
const a=1 //const 是声明时必须赋值,且不能再改的方式
a = 1
这种方式是错误的,不准这样声明
2.1.1 let 声明规则
-
遵循块作用域,即:使用范围不能超出 { }
-
不能重复申明
-
可以赋值,也可以不赋值
-
必须先声明,再使用。否则报错
-
全局声明的 let 变量,不会变成 window 的属性
这其实是 var 的 bug 。为什么声明变量会变成 window 上的属性?这是var强加的;
let就改掉这个bug了,let就是单纯声明变量,不做多余操作 -
for 循环配合 let 有奇效
🌟 推荐书阅读: 我用了两个月的时间才理解 let
2.1.2 const 声明规则
- 几乎和 let 一样
- 只有一条不一样:声明时就要赋值,赋值后不能改(有且仅有一次赋值)。const 声明的是一个 只读变量,也叫做「常量」
- for循环配合const变量也会报错,原因同上,因为const是常量,不能改变
⚠️注意
变量声明在指定 值 的同时也指定了 类型
name // name是个变量,存在「不知什么区」,name的值是可以变的,类型也可以是任何类型
'name' // 'name'是个字符串常量,存在stack区,值变不了
2.2 标识符
标识符是指变量的合法命名。规则如下:
- 第一个字符,可以是任意Unicode字母(包括英文字母、拉丁字母等)、下划线_、$符号、中文,不可以是数字开头
- 第二个字符及后面的字符,除了上述所说,还可以是数字
如图所示,如果用数字作为变量名的开头,会报错
2.3 注释
// 1. 单行注释
/*
2. 多行注释
多行注释
*/
好的注释
① 踩坑注解
② 为什么代码会写得这么奇怪,遇到什么 bug,怎样避开这个 bug
不好的注释
① 把代码翻译成中文(可能埋没了重要的注释)
② 过时的注释
③ 发泄不满的注释
3. 表达式和语句的区别
- 表达式一般都有值,语句可能有也可能没有
- 语句一般会改变环境(声明,赋值)
- 上面两句话并不绝对 ⚠️注意
- JS大小写敏感
- 大部分空格没有意义,加回车大部分时候也不影响
- ★只有一个地方不能加回车,就是 return 后面,如果加了,JS 会自动补 undefined
「二」 条件语句
1. if...else 语句
if(表达式) {语句1} else {语句2}
⚠️注意
-
{ } 在语句只有一句的时候可以省略,不建议这样做 ∴ 注意缩进
因为不写 { } 时,只默认第一个语句是跟随 if 条件的
-
逗号表示这句话没完,分号表示这句话完了
∴ 永远不要省略花括号 { },即使只有一个语句。使用最没有歧义的写法
2. switch 语句
不推荐,但有些时候比 if…else… 好用
switch(fruit){
case "banana":
//...
break;
case "apple":
//...
break;
default:
//...
}
/* 每个case都需要写一个break,
否则,如果banana没有break, 那么它会继续执行apple的部分,
直到碰到了break*/
- 大部分时候不要省略break,小部分时候可以利用break分类
switch(num){
case 1:
case 3:
case 5:
console.log("输出单数");
break;
case 2:
case 4:
case 6:
console.log("输出偶数");
break;
}
3. 三元运算符 ?: (问号冒号表达式)
最简单的if... else...
表达式1 ? 表达式2 : 表达式3 //若表达式1 为真,执行表达式2;若表达式1 为假,执行表达式3
4. 短路逻辑 ⭐
也可以代替if...else...
前端中,如果能写成 &&
/||
的语句,就不写 if…else…
语句
4.1 && 短路逻辑
- A && B && C && D取第一个假值,后面就不看了,如果ABC都为真,就取 D;
- 并不会取 true / false
a&&b
// a&&b 等价于,如果a是真,就执行b
if(a){
b
}
if (window.f1) {
console.log('f1存在')
}
// 等价于
window.f1 && console.log('f1存在')
常用例子:fn && fn()
( 判断函数是否存在,若fn 存在就执行 fn )
4.2 || 短路逻辑
- A || B || C || D 取第一个真值或 D
- 并不会取 true / false
a||b
// a||b 等价于, 如果a是假,就执行b
if(!a) {
b
}
// 保底值
// 如果a存在, a=a; 如果a不存在, a=100
a = a || 100
// 等价于
if (a) {
a = a
} else {
a = 100
}
常用例子: A = A || B
(A 存在时就什么都不执行,A 不存在时 B 就是 A 的保底值)
「三」 循环语句
1. while 循环
while
循环用得少 ( do...while用得很少,自行了解,这里不做说明)
while (表达式) {语句}
var a = 1 // 初始化
while(a !== 10){ // 判断条件
console.log(a) // 循环体
a = a+1 // 增长(为最终能跳出循环)
}
- 判断表达式的真假;当表达式为真,执行语句;执行完再判断表达式的真假, 直到遇到表达式为假,跳出循环;执行后面的语句
- 共需要四部分: 1. 初始化 2. 判断条件 3. 循环体 4. 增长
- while循环的语法和if非常相似,但区别是,只要给定条件的结果是true,那花括号中的代码就会反复执行下去
⚠️注意
// while (true) 死循环
let a = 0.1;
while (a !== 1) {
console.log(a)
a = a + 0.1
}
∵ 浮点数的计算是不精确的
∴ 永远不可能加到1,以上代码会死循环,会占着CPU什么也不做
2. for 循环
for
循环是 while
循环的方便写法
for(语句1; 表达式2; 语句3) {
循环体
}
// 语句1是是while循环中的初始化,表达式2是判断,语句3是增长
- 先执行语句1
- 然后判断表达式2
- 若为真,执行循环体,再执行语句3,然后继续判断表达式2
- 若为假,直接退出循环,执行后面的语句
for(let i=0; i<5; i++){
console.log(i) // 0 1 2 3 4
}
console.log(i) // i 是 5,因为循环体执行完会再执行语句3
for (let i = 0; i < 5; i++) {
console.log(i) // 0 1 2 3 4
}
console.log(i) // i 是 undefined,因为let声明的变量不会变量提升
- for循环配合let有奇效 见前面let声明变量(点击即可预览)
3. break 和 continue
break
退出当前for的所有循环continue
退出当前一次,下次继续
for(var i=0; i<10; i++) {
if(i%2 === 1){
break // 遇到奇数,就退出整个for循环
}
}
console.log(i) // 1
for(var i=0; i<10; i++){
if(i%2 === 1){
continue // 遇到奇数,就跳过当次循环
} else {
console.log(i) // 0 2 4 6 8
}
}
- 循环嵌套时,
break
退出离他最近的一个for循环
for (var i = 0; i < 10; i++) {
for (var j = 0; j < 5; j++) {
if (i===5) {
break;
}
}
console.log(i) // 会打印出0,1,2,3,4,5,6,7,8,9
// 因为break只会退出离他最近的一个for循环,只是当前for的所有循环
}
4. 标签(label)
很少用,面试可能会涉及,基本没什么用处
{
foo:1;
}
以上代码不是一个对象! 以上的代码是有一个代码块,里面有一个label, foo: 1 表示这个标签是foo, foo的值是1
下方代码就是一个对象了
var a = {
foo: 1
}