基础知识
script
JavaScript 是一种脚本语言,主要的作用是在网页中添加动态功能。
引入方式
- 内联方式
<script>let a = 1;</script>
- 外部方式
<script src="./a.js"></script>
属性:
- async
- defer
代码结构
alert("hello");
// 注释
// let a = 1;
/* let b = 2;*/
- 分号结尾,可以省略。
- 注释:两种注释形势
现代模式
"use strict";
- 必须在脚本的第一行。
- 不声明变量会报错。
- 声明后不可取消。
class
和module
会自动启动严格模式。
变量
- var:变量可以重复声明,并且会涉及到变量提升。
- let:变量不可以重复声明,并且不会涉及变量提升。
- const:变量不可重复声明,不可以重新赋值,并且不会涉及变量提升。但是对象或数组中可以修改属性或值。
var a = 1;
let b = 2;
const c = 3;
b = 4;
c = 5; //报错
命名限制:
- 必须仅包含字母、数字、_、$符号。
- 首字符必须是非数字。
注意:
- 变量名区分大小写。
- 变量名不能是保留字。
- 允许非英文字母,但是不推荐。
数据类型
- 基本数据类型:number、string、boolean、null、undefined、symbol、bigint
- 引用数据类型:object
Number
表示整数和浮点数。
特殊值:
- Infinity:正无穷
- -Infinity:负无穷
- NaN:非数字(比较特殊,如果数学表达式中有一个 NaN,则整个表达式的结果就是 NaN。只有一个例外
NaN ** 0
结果为 1)。
BigInt
在 JavaScript 中,number 无法安全的表示大于 2^53 - 1
或小于-2^53 - 1
的整数,这被称为 “精度丢失”。
例如:
console.log(9007199254740991 + 1); // 9007199254740992
console.log(9007199254740991 + 2); // 9007199254740992
BigInt
式最近被添加到 JavaScriot 中的。用于表示任意长度的整数。
格式:
const bigNumber = 1234567890123456789012345678901234567890n;
String
字符串是由零个或多个字符组成的字符序列。
在 JavaScript 中,字符串是不可变的。一旦创建,它们不能被修改。有三种包含字符串的方式。
- 双引号:
"hello"
; - 单引号:
'hello'
; - 反引号:
hello
;
Boolean
布尔值只有两个值:true
和false
。正确或者不正确。
null 和 undefined
- null:表示的是空值。
- undefined:表示的是未定义。
Object 类型和 Symbol 类型
Object
是一个特殊的类型。
其他所有的数据类型都被称为原始类型,因为他们的值只包含一个单独的内容。Object 则是用于存储数据集合和更复杂的实体。
symbol
类型用于创建对象的唯一标识符。
typeof
返回参数的类型(string 类型)
格式:
- typeof x
- typeof(x)
typeof 1; //"number"
typeof "hello"; //"string"
typeof true; //"boolean"
typeof null; //"object"//bug ,null不是一个对象是一个特殊值。是一个遗留问题,为了兼容保留的。
typeof undefined; //"undefined"
typeof Symbol("id"); //"symbol"
typeof BigInt(1); //"bigint"
typeof Math; //"object"
typeof alert; //"function"
类型转换
字符串转换
字符串的转换很简单,只需要使用String()
函数即可。
let value = true;
alert(typeof value); //boolean
value = String(value);
alert(typeof value); //string
数字转换
在算术函数和表达式中,会自动进行 number 类型转换。 如:当把除法 /
用于非 number 类型。
alert("6" / "2"); //3
- Number(value) 显式转换
转换规则:
值 | 变成 |
---|---|
undefined | NaN |
null | 0 |
true 和 false | 1 and 0 |
string | 去掉首尾空白字符(空格、换行符\n 、制表符 \t 等)后的纯数字字符串中含有的数字。如果剩余字符串为空,则转换结果为0 。否则,将会从剩余字符串中"读取"数字,当类型转换出现 error 时返回NaN |
alert(Number(" 123 ")); // 123
alert(Number("123z")); // NaN(从字符串“读取”数字,读到 "z" 时出现错误)
alert(Number(true)); // 1
alert(Number(false)); // 0
布尔型转换
布尔类型转换时最简单的一个。
转换规则如下:
- 直观上为"空"的值(如
0
、空字符串、null
、undefined
和NaN
)将变为false
。 - 其他值变为
true
。值 变成 0
、空字符串、null
、undefined
和NaN
)false
其他值 true
运算符、数学运算
术语:一元运算符、二元运算符、运算元
- 运算元:运算符的参数,比如
5*2
5 和 2 就是两个运算元,也被称为参数 - 一元运算符:只有一个运算元,比如
++
、--
- 二元运算符:有两个运算元,比如
+
、-
、*
、/
、%
数学运算
- 加法:
+
- 减法:
-
- 乘法:
*
- 除法:
/
- 取余:
%
- 求幂:
**
取余:
alert(5 % 2); //1
alert(8 % 3); //2
求幂
alert(2 ** 2); //2^2 = 4
二元运算符 +
通常情况下 +
用于求和。
但是当运算元中有一个是字符串时,+
会进行字符串连接。
let a = "123";
let b = "hello";
console.log(a + b); //'123hello'
一元运算符 +
+
也可以用于将字符串转换为数字。
let a = "123";
let b = "hello";
console.log(+a); //123
console.log(+b); //NaN
运算符优先级
优先级 | 名称 | 符号 |
---|---|---|
... | ... | ... |
15 | 一元加号 | + |
15 | 一元负号 | - |
14 | 求幂 | ** |
13 | 乘号 | * |
13 | 除号 | / |
12 | 加号 | + |
12 | 减号 | - |
... | ... | ... |
2 | 赋值符 | = |
... | ... | ... |
这就是为什么+apples + oranges
中的一元加号先生效,然后才是二元加法。
赋值运算符
格式:
赋值 = 返回一个值
=
是一个运算符,但是它的优先级比较低,所以a = b = c
会先计算b = c
,然后再计算a = b
。
原地修改
+=、-=、*=、/=等,它们表示的含义都是一样的比如
let a = 1;
a += 2;
console.log(a); //3
// ======等同于
let a = 1;
a = a + 2;
console.log(a);
自增/自减
只能用于变量,不能用于数字。
++
--
let a = 1;
a++;
console.log(a); //2
let b = 2;
b--;
console.log(b); //1
前置和后置的区别:
- 前置:counter++
- 后置:++counter
两者都是做了同一件事:将变量 counter 加 1。区别在于返回值的不同。
let a = 1;
let count = a++;
console.log(count); //1
let b = 1;
let count2 = ++b;
console.log(count2); //2
位运算符
位运算符把运算元当作 32 位的整数,并在该整数的二进制表现形式上操作。
- 按位与(
&
) - 按位或(
|
) - 按位异或(
^
) - 按位非(
~
) - 左移(
<<
) - 右移(
>>
) - 无符号右移(
>>>
)
主要用在特殊领域(例如密码学),一般开发不会用到。 位操作符
逗号运算符
逗号运算符用于对两个表达式求值,并返回第二个表达式的值。
优先级非常低,比 =
还要低。
let a = (1 + 2, 3 + 4);
console.log(a); //7
值的比较
比较结果为 Boolean 类型
所有比较运算符均返回布尔值。
- true --- 表示“yes (是)”,
- false --- 表示“no (否)”
字符串比较
在比较字符串的大小时,JavaScript 会使用字典(dictionary)或词典(lexicographical)顺序进行判定。
换个说法就是,字符串是按字符逐个进行比较的。
- 首先比较两个字符串的首位字符大小。
- 如果一方字符较大(或较小),改字符串大于(或小于)另一个字符串,算法结束。
- 否则,如果两个字符串的首位字符相等,则继续取出两个字符串个字的后一位字符进行比较。
- 重复上述步骤进行比较,直到比较完成某字符的所有字符为止。
- 如果两个字符串的字符同时用完,那么则判定它们相等,否则未结束(还有未比较的字符)的字符串更大。
比较的依照是Unicode
编码顺序。
不同类型间的比较
当不同类型的值进行比较时,JavaScript 会首先将其转换为数字(number)再判定大小。
例如:
alert("2" > 1); // true,字符串 '2' 会被转化为数字 2
alert("01" == 1); // true,字符串 '01' 会被转化为数字 1
对于布尔类型值,true
会被转化为1
,false
会被转化为0
。
alert(true == 1); // true
alert(false == 0); // true
严格相等
===
和!==
运算符会同时比较值和类型。
对 null 和 undefined 的比较
当使用null
或undefined
与其他值进行比较时,当使用严格相等比较时,它们不相等。
当使用非严格相等比较时,JavaScript 存在一个特殊的规则,会判定它们相等。
当使用数学式或其他比较方法<
、>
、<=
、>=
时: null/undefined
会被转换为数字:null
会被转换为0
,undefined
被转换为NaN
。
奇怪的结果:null vs 0
console.log(null > 0); //false
console.log(null == 0); //false
console.log(null >= 0); //true
原因:因为在相等性检查==
和普通比较符>
、<
、>=
、<=
的代码逻辑是相互独立的。进行值的比较时,null 会被转换为数字 0.
另外 undefined
和null
在相等性检查==
中不会进行任何类型转换,它们只是单纯的相等。
特殊的 undefined
undefined
不应该与其他值进行比较。
console.log(undefined > 0); //false
console.log(undefined < 0); //false
console.log(undefined == 0); //false
避免问题
- 除了严格相等
===
时,其他有undefined/null
比较时都需要小心处理。 - 对于取值可能是
null/undefined
的值请使用===
。
条件分支:if 和'?'
格式:
//type会被转换为布尔值
// 0、""、null、undefined、NaN、false 为假,其余为真
if (type) {
} else if (type) {
} else {
}
三目运算符
格式:
a === 1 ? true : false;
逻辑运算符
&&
逻辑与||
逻辑或!
逻辑非
逻辑或
result = a || b || c;
或运算符||
做了如下的事情
- 从左到右依次计算操作数。
- 处理每一个操作数时,都会将其转换为布尔值。如果结果是
true
,就停止计算,返回这个操作数的初始值。 - 如果所有的操作数都被计算过,都是 false 的话,返回最后一个操作数。
短路求值:
let a = 0;
let b = a || 2; //b=2;
逻辑与
result = a && b && c;
与运算符&&
做了如下的事情
- 从左到右依次计算操作数。
- 处理每一个操作数时,都会将其转换为布尔值。如果结果是
false
,就停止计算,返回这个操作数的初始值。 - 如果所有的操作数都被计算过,都是 true 的话,返回最后一个操作数。
!(非)
取反
result = !value;
- 将操作数转化为布尔类型:
true/false
- 返回相反的值。
优先级
&&
比||
的优先级要高。所以a && b || c && d
和(a && b) || (c && d)
是完全一样的。 !
是这三个运算符中优先级最高的。
空值合并运算符 ??
result = a ?? b;
// 等价于
result = a !== null && a !== undefined ? a : b;
仅当a
为null/undefined
时,返回b
,否则返回a
。
与 ||
的区别
||
返回第一个 真 值??
返回第一个 已定义 的值
注意: ??
和||
的优先级是相通的,但是不要吧??
、||
、&&
一起使用,除非你明确知道判断的顺序。
循环 while、for、do...while
while
格式:
let i = 0;
while (i < 3) {
console.log(i);
i++;
}
do...while
格式:
let i = 0;
do {
console.log(i);
i++;
} while (i < 3);
和 while
的区别是,do...whild
循环至少会执行一次。
for
格式:
for (begin; condition; step) {
//循环体
}
for (let i = 0; i < 3; i++) {
console.log(i);
}
语句 | 具体 | 含义 |
---|---|---|
begin | let i = 0 | 进入循环时执行一次 |
condtion | i < 3 | 在每次循环迭代之前检查,如果是 false,停止循环 |
body(循环体) | console.log(i) | 条件为真时,重复运行 |
step | i++ | 在每次循环体迭代后执行 |
省略语句:
//省略begin
let i = 0;
for (; i < 3; i++) {
console.log(i);
}
//省略step
for (let i = 0; i < 3; ) {
console.log(i);
i++;
}
//无限循环
for (;;) {
//无限循环
}
跳出循环
break
:立即退出循环continue
:跳过当前迭代,进入下一次迭代
可控的跳出循环
格式:
labelName:for(...){
...
}
outer: for (let i = 0; i < 3; i++) {
outer1: for (let j = 0; j < 3; j++) {
let input = prompt(`Value at coords (${i},${j})`, "");
// 如果是空字符串或被取消,则中断并跳出这两个循环。
if (!input) break outer; // (*)
console.log(input);
if (input === 1) continue outer1;
}
}
switch 语法
作用:替代多个if
判断。
格式:
switch(type){
case value1:
//...
break;
case value2:
//...
break;
default:
//...最终处理位置
}
注意:switch
的比对是全量等价比对(===
)
函数
函数声明
function name(parameter1,parameter2,...parametersN){
//...函数体
}
局部变量
在es6之前,js只有一种方式可以制造局部变量,就是通过函数的方式。局部变量牵扯到作用域,就像房子的门的猫眼,内部可以看到外面的情况,但是外部看不到内部。
function sayHi(){
const a = 1;
console.log(a)//1
}
console.log(a);//报错
参数
function sum(a,b){//形参
//...
}
sum(1,2)//实参
默认参数 与 返回值
function sum(a,b=0){
return a + b;
}
const sum_value = sum(1);//注意这不是错误,函数的参数并不是固定的,可以不传。
console.log(sum_value);// sum_value 就是用来接sum的返回值
函数命名
函数就是行为(action)。所以它们的名字通常是动词。它应该简短切尽可能描述函数的作用。
- "get" 返回一个值。
- "calc" 计算某些内容。
- "create" 创建某些内容。
- "check" 检查某些内容并返回boolean的值。
函数 == 注释
一个函数应该简短且只有一个功能。如果函数功能复杂,那么该函数应该被拆分成几个小的函数。这就是函数式编程的基本思想。
函数表达式
//函数声明
function sum(a,b){
return a + b;
}
//函数表达式
const sum = function(a,b){
return a + b;
}
函数是一个值
不管是函数声明还是函数表达式,它们都是一个特殊的值。
function sayHi(){
alert('Hello');
}
let func = sayHi;
func();//Hello;
sayHi();//Hello;
回调函数
function ask(question, yes, no) {
if (confirm(question)) yes()
else no();
}
function showOk() {
alert("You agreed.");
}
function showCancel() {
alert("You canceled the execution.");
}
// 使用函数表达式
ask("Do you agree?", showOk, showCancel);
函数表达式 VS 函数声明
区别:
- 格式不同
- 创建的时机不同,函数声明会在代码执行前创建,而函数表达式会在代码执行到它的时候创建。
箭头函数
let func = (arg1,arg2,...argN) => expression;
//等价于
let func = function(arg1,arg2,...argN){
return expression;
}
当只有一个参数时,可以省略括号。当只有一个返回语句且是return结果时。可以对函数体进行简写。