JavaScript 基础知识 1


#JavaScript 基础知识
##Hello, world!
“script” 标签
JavaScript 程序可以在 <script> 标签的帮助下插入到 HTML 文档的任何地方。
<script>
alert('Hello, world!');
</script>
<script> 标签中包裹了 JavaScript 代码,当浏览器遇到 <script> 标签,代码会自动运行。

外部脚本
脚本文件可以通过 src 特性(attribute)添加到 HTML 文件中。
<script src="/path/to/script.js"></script>
这里,/path/to/script.js 是脚本文件从网站根目录开始的绝对路径。当然也可以提供当前页面的相对路径。例如,src ="script.js" 表示当前文件夹中的 "script.js" 文件。
也可以提供一个完整的 URL 地址,例如:
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.js"></script>
要附加多个脚本,请使用多个标签:
<script src="/js/script1.js"></script>
<script src="/js/script2.js"></script>

注意
如果设置了 src 特性,script 标签内容将会被忽略。
一个单独的 <script> 标签不能同时有 src 特性和内部包裹的代码。
<script src="file.js">
alert(1); // 此内容会被忽略,因为设定了 src
</script>
为了让上面的例子工作,我们可以将它分成两个 <script> 标签。
<script src="file.js"></script>
<script>
alert(1);
</script>

代码结构
我们将要学习的第一个内容就是构建代码块。
语句
语句是执行行为(action)的语法结构和命令。
语句之间可以使用分号进行分割。
例如,我们将 “Hello World” 这条信息一分为二:
alert('Hello'); alert('World');

注释
单行注释以两个正斜杠字符 // 开始。
多行注释以一个正斜杠和星号开始 “/*” 并以一个星号和正斜杠结束 “*/”。

使用热键!
在大多数的编辑器中,一行代码可以使用 Ctrl+/ 热键进行单行注释,诸如 Ctrl+Shift+/ 的热键可以进行多行注释(选择代码,然后按下热键)。对于 Mac 电脑,应使用 Cmd 而不是 Ctrl,使用 Option 而不是 Shift。

不支持注释嵌套!
不要在 /*...*/ 内嵌套另一个 /*...*/。

现代模式,"use strict"
“use strict”
这个指令看上去像一个字符串 "use strict"; 或者 'use strict'; 。当它处于脚本文件的顶部时,则整个脚本文件都将以“现代”模式进行工作。

变量
变量
变量 是数据的“命名存储”。
在 JavaScript 中创建一个变量,我们需要用到 let 关键字。
下面的语句创建(也可以称为 声明 或者 定义)了一个名称为 “message” 的变量:
let message;
message = 'Hello!';

let message = 'Hello!';

也可以在一行中声明多个变量:
let user = 'John', age = 25, message = 'Hello';

当变量值改变的时候,之前的数据就被从变量中删除了:

还可以声明两个变量,然后将其中一个变量的数据拷贝到另一个变量。
let hello = 'Hello world!';
let message;
// 将字符串 'Hello world' 从变量 hello 拷贝到 message
message = hello;
// 现在两个变量保存着相同的数据
alert(hello); // Hello world!
alert(message); // Hello world!

声明两次会触发 error
一个变量应该只被声明一次。
对同一个变量进行重复声明会触发 error:
因此,我们对同一个变量应该只声明一次,之后在不使用 let 的情况下对其进行引用。

变量命名
JavaScript 的变量命名有两个限制:
变量名称必须仅包含字母,数字,符号 $ 和 _。
首字符必须非数字。

如果命名包括多个单词,通常采用驼峰式命名法(camelCase)

常量
声明一个常数(不变)变量,可以使用 const 而非 let:
const myBirthday = '18.04.1982';
使用 const 声明的变量称为“常量”。它们不能被修改,如果你尝试修改就会发现报错:

#数据类型
在 JavaScript 中有 8 种基本的数据类型(译注:7 种原始类型和 1 种引用类型)。
Number 类型
number 类型代表整数和浮点数。
数字可以有很多操作,比如,乘法 *、除法 /、加法 +、减法 - 等等。
除了常规的数字,还包括所谓的“特殊数值(“special numeric values”)”也属于这种类型:Infinity、-Infinity 和 NaN。
Infinity 代表数学概念中的 无穷大 ∞。是一个比任何数字都大的特殊值。
NaN 代表一个计算错误。它是一个不正确的或者一个未定义的数学操作所得到的结果
NaN 是粘性的。任何对 NaN 的进一步操作都会返回 NaN:
alert( "not a number" / 2 + 5 ); // NaN

BigInt 类型
可以通过将 n 附加到整数字段的末尾来创建 BigInt 值。
// 尾部的 "n" 表示这是一个 BigInt 类型
const bigInt = 1234567890123456789012345678901234567890n;

String 类型
JavaScript 中的字符串必须被括在引号里。
在 JavaScript 中,有三种包含字符串的方式。

双引号:"Hello".
单引号:'Hello'.
反引号:`Hello`.

双引号和单引号都是“简单”引用,在 JavaScript 中两者几乎没有什么差别。

反引号是 功能扩展 引号。它们允许我们通过将变量和表达式包装在 ${…} 中,来将它们嵌入到字符串中。例如:

let name = "John";
// 嵌入一个变量
alert( `Hello, ${name}!` ); // Hello, John!
// 嵌入一个表达式
alert( `the result is ${1 + 2}` ); // the result is 3

Boolean 类型(逻辑类型)
boolean 类型仅包含两个值:true 和 false。

“null” 值
特殊的 null 值不属于上述任何一种类型。
它构成了一个独立的类型,只包含 null 值:
let age = null;

“undefined” 值
特殊值 undefined 和 null 一样自成类型。
undefined 的含义是 未被赋值。
如果一个变量已被声明,但未被赋值,那么它的值就是 undefined:
let age;
alert(age); // 弹出 "undefined"

object 类型和 symbol 类型
object 类型是一个特殊的类型。symbol 类型用于创建对象的唯一标识符。

typeof 运算符
typeof 运算符返回参数的类型。
它支持两种语法形式:
作为运算符:typeof x。
函数形式:typeof(x)。

总结
JavaScript 中有八种基本的数据类型(译注:前七种为基本数据类型,也称为原始类型,而 object 为复杂数据类型)。

number 用于任何类型的数字:整数或浮点数,在 ±(253-1) 范围内的整数。
bigint 用于任意长度的整数。
string 用于字符串:一个字符串可以包含 0 个或多个字符,所以没有单独的单字符类型。
boolean 用于 true 和 false。
null 用于未知的值 —— 只有一个 null 值的独立类型。
undefined 用于未定义的值 —— 只有一个 undefined 值的独立类型。
symbol 用于唯一的标识符。
object 用于更复杂的数据结构。
我们可以通过 typeof 运算符查看存储在变量中的数据类型。

两种形式:typeof x 或者 typeof(x)。
以字符串的形式返回类型名称,例如 "string"。
typeof null 会返回 "object" —— 这是 JavaScript 编程语言的一个错误,实际上它并不是一个 object。

#交互:alert、prompt 和 confirm
alert
alert("Hello");

prompt
prompt 函数接收两个参数:

result = prompt(title, [default]);
浏览器会显示一个带有文本消息的模态窗口,还有 input 框和确定/取消按钮。

title
显示给用户的文本
default
可选的第二个参数,指定 input 框的初始值。

语法中的方括号 [...]
上述语法中 default 周围的方括号表示该参数是可选的,不是必需的。

confirm
语法:
result = confirm(question);
confirm 函数显示一个带有 question 以及确定和取消两个按钮的模态窗口。
点击确定返回 true,点击取消返回 false。

例如:
let isBoss = confirm("Are you the boss?");
alert( isBoss ); // 如果“确定”按钮被按下,则显示 true

总结
我们学习了与用户交互的 3 个浏览器的特定函数:

alert
显示信息。
prompt
显示信息要求用户输入文本。点击确定返回文本,点击取消或按下 Esc 键返回 null。
confirm
显示信息等待用户点击确定或取消。点击确定返回 true,点击取消或按下 Esc 键返回 false。
这些方法都是模态的:它们暂停脚本的执行,并且不允许用户与该页面的其余部分进行交互,直到窗口被解除。

上述所有方法共有两个限制:
模态窗口的确切位置由浏览器决定。通常在页面中心。
窗口的确切外观也取决于浏览器。我们不能修改它。

#类型转换
总结
有三种常用的类型转换:转换为 string 类型、转换为 number 类型和转换为 boolean 类型。

字符串转换 —— 转换发生在输出内容的时候,也可以通过 String(value) 进行显式转换。原始类型值的 string 类型转换通常是很明显的。

数字型转换 —— 转换发生在进行算术操作时,也可以通过 Number(value) 进行显式转换。

数字型转换遵循以下规则:

值 变成……
undefined NaN
null 0
true / false 1 / 0
string “按原样读取”字符串,两端的空白会被忽略。空字符串变成 0。转换出错则输出 NaN。
布尔型转换 —— 转换发生在进行逻辑操作时,也可以通过 Boolean(value) 进行显式转换。

布尔型转换遵循以下规则:

值 变成……
0, null, undefined, NaN, "" false
其他值 true
上述的大多数规则都容易理解和记忆。人们通常会犯错误的值得注意的例子有以下几个:

对 undefined 进行数字型转换时,输出结果为 NaN,而非 0。
对 "0" 和只有空格的字符串(比如:" ")进行布尔型转换时,输出结果为 true。

#基础运算符,数学
术语:“一元运算符”,“二元运算符”,“运算元”
运算元 —— 运算符应用的对象。比如说乘法运算 5 * 2,有两个运算元:左运算元 5 和右运算元 2。
如果一个运算符对应的只有一个运算元,那么它是 一元运算符。
如果一个运算符拥有两个运算元,那么它是 二元运算符。减号还存在二元运算符形式:

数学
支持以下数学运算:
加法 +,
减法 -,
乘法 *,
除法 /,
取余 %,
求幂 **.
前四个都很简单,而 % 和 ** 则需要说一说。

取余 %
取余运算符是 %,尽管它看起来很像百分数,但实际并无关联。
a % b 的结果是 a 整除 b 的 余数)。

求幂 **
求幂运算 a ** b 是 a 乘以自身 b 次。

用二元运算符 + 连接字符串
通常,加号 + 用于求和。
但是如果加号 + 被应用于字符串,它将合并(连接)各个字符串:
一个更复杂的例子
alert(2 + 2 + '1' ); // "41",不是 "221"
在这里,运算符是按顺序工作。
第一个 + 将两个数字相加,所以返回 4,然后下一个 + 将字符串 1 加入其中,所以就是 4 + '1' = 41。

二元 + 是唯一一个以这种方式支持字符串的运算符。其他算术运算符只对数字起作用,并且总是将其运算元转换为数字。
下面是减法和除法运算的示例:
alert( 6 - '2' ); // 4,将 '2' 转换为数字
alert( '6' / '2' ); // 3,将两个运算元都转换为数字


数字转化,一元运算符 +
加号 + 有两种形式。一种是上面我们刚刚讨论的二元运算符,还有一种是一元运算符。
一元运算符加号,或者说,加号 + 应用于单个值,对数字没有任何作用。但是如果运算元不是数字,加号 + 则会将其转化为数字。
例如:
// 对数字无效
let x = 1;
alert( +x ); // 1

let y = -2;
alert( +y ); // -2

// 转化非数字
alert( +true ); // 1
alert( +"" ); // 0

运算符优先级
表达式 1 + 2 * 2 中,乘法先于加法计算。这就是一个优先级问题。乘法比加法拥有 更高的优先级。
圆括号拥有最高优先级,所以如果我们对现有的运算顺序不满意,我们可以使用圆括号来修改运算顺序,就像这样:(1 + 2) * 2。
在 JavaScript 中有众多运算符。每个运算符都有对应的优先级数字。数字越大,越先执行。如果优先级相同,则按照由左至右的顺序执行。

原地修改
我们经常需要对一个变量做运算,并将新的结果存储在同一个变量中。
可以使用运算符 += 和 *= 来缩写这种表示。
let n = 2;
n += 5; // 现在 n = 7(等同于 n = n + 5)
n *= 2; // 现在 n = 14(等同于 n = n * 2)
alert( n ); // 14

所有算术和位运算符都有简短的“修改并赋值”运算符:/= 和 -= 等。
这类运算符的优先级与普通赋值运算符的优先级相同,所以它们在大多数其他运算之后执行:

let n = 2;
n *= 3 + 5;
alert( n ); // 16 (右边部分先被计算,等同于 n *= 8)

自增/自减
自增 ++ 将变量与 1 相加:

let counter = 2;
counter++; // 和 counter = counter + 1 效果一样,但是更简洁
alert( counter ); // 3

自减 -- 将变量与 1 相减:

let counter = 2;
counter--; // 和 counter = counter - 1 效果一样,但是更简洁
alert( counter ); // 1

重要:
自增/自减只能应用于变量。试一下,将其应用于数值(比如 5++)则会报错。

运算符 ++ 和 -- 可以置于变量前,也可以置于变量后。

当运算符置于变量后,被称为“后置形式”:counter++。
当运算符置于变量前,被称为“前置形式”:++counter。
两者都做同一件事:将变量 counter 与 1 相加。

那么它们有区别吗?有,但只有当我们使用 ++/-- 的返回值时才能看到区别。

如果自增/自减的值不会被使用,那么两者形式没有区别:

let counter = 0;
counter++;
++counter;
alert( counter ); // 2,以上两行作用相同
如果我们想要对变量进行自增操作,并且 需要立刻使用自增后的值,那么我们需要使用前置形式:

let counter = 0;
alert( ++counter ); // 1
如果我们想要将一个数加一,但是我们想使用其自增之前的值,那么我们需要使用后置形式:

let counter = 0;
alert( counter++ ); // 0

++/-- 运算符同样可以在表达式内部使用。它们的优先级比绝大部分的算数运算符要高。

位运算符
下面是位运算符:

按位与 ( & )
按位或 ( | )
按位异或 ( ^ )
按位非 ( ~ )
左移 ( << )
右移 ( >> )
无符号右移 ( >>> )

逗号运算符
逗号运算符 , 是最少见最不常使用的运算符之一。
举个例子:
let a = (1 + 2, 3 + 4);
alert( a ); // 7(3 + 4 的结果)
逗号运算符的优先级非常低
请注意逗号运算符的优先级非常低,比 = 还要低,因此上面你的例子中圆括号非常重要。
如果没有圆括号:a = 1 + 2, 3 + 4 会先执行 +,将数值相加得到 a = 3, 7,然后赋值运算符 = 执行 a = 3,然后逗号之后的数值 7 不会再执行,它被忽略掉了。相当于 (a = 1 + 2), 3 + 4。

下面这些表达式的结果是什么?
"" + 1 + 0 = "10" // (1)
"" - 1 + 0 = -1 // (2)
true + false = 1
6 / "3" = 2
"2" * "3" = 6
4 + 5 + "px" = "9px"
"$" + 4 + 5 = "$45"
"4" - 2 = 2
"4px" - 2 = NaN
7 / 0 = Infinity
" -9 " + 5 = " -9 5" // (3)
" -9 " - 5 = -14 // (4)
null + 1 = 1 // (5)
undefined + 1 = NaN // (6)
" \t \n" - 2 = -2 // (7)
有字符串的加法 "" + 1,首先会将数字 1 转换为一个字符串:"" + 1 = "1",然后我们得到 "1" + 0,再次应用同样的规则得到最终的结果。
减法 -(像大多数数学运算一样)只能用于数字,它会使空字符串 "" 转换为 0。
带字符串的加法会将数字 5 加到字符串之后。
减法始终将字符串转换为数字,因此它会使 " -9 " 转换为数字 -9(忽略了字符串首尾的空格)。
null 经过数字转换之后会变为 0。
undefined 经过数字转换之后会变为 NaN。
字符串转换为数字时,会忽略字符串的首尾处的空格字符。在这里,整个字符串由空格字符组成,包括 \t、\n 以及它们之间的“常规”空格。因此,类似于空字符串,所以会变为 0。

#值的比较
在 JavaScript 中,它们的编写方式如下:

大于 / 小于:a > b,a < b。
大于等于 / 小于等于:a >= b,a <= b。
检查两个值的相等:a == b,请注意双等号 == 表示相等性检查,而单等号 a = b 表示赋值。
检查两个值不相等。不相等在数学中的符号是 ≠,但在 JavaScript 中写成 a != b。

比较结果为 Boolean 类型
所有比较运算符均返回布尔值:
true —— 表示“yes(是)”,“correct(正确)”或“the truth(真)”。
false —— 表示“no(否)”,“wrong(错误)”或“not the truth(非真)”。

字符串比较
在比较字符串的大小时,JavaScript 会使用“字典(dictionary)”或“词典(lexicographical)”顺序进行判定。
换言之,字符串是按字符(母)逐个进行比较的。

非真正的字典顺序,而是 Unicode 编码顺序
在上面的算法中,比较大小的逻辑与字典或电话簿中的排序很像,但也不完全相同。
比如说,字符串比较对字母大小写是敏感的。大写的 "A" 并不等于小写的 "a"。哪一个更大呢?实际上小写的 "a" 更大。这是因为在 JavaScript 使用的内部编码表中(Unicode),小写字母的字符索引值更大。我们会在 字符串 这章讨论更多关于字符串的细节。

不同类型间的比较
当对不同类型的值进行比较时,JavaScript 会首先将其转化为数字(number)再判定大小。
例如:
alert( '2' > 1 ); // true,字符串 '2' 会被转化为数字 2
alert( '01' == 1 ); // true,字符串 '01' 会被转化为数字 1

对于布尔类型值,true 会被转化为 1、false 转化为 0。

严格相等
普通的相等性检查 == 存在一个问题,它不能区分出 0 和 false:
alert( 0 == false ); // true
也同样无法区分空字符串和 false:
alert( '' == false ); // true
这是因为在比较不同类型的值时,处于相等判断符号 == 两侧的值会先被转化为数字。空字符串和 false 也是如此,转化后它们都为数字 0。

严格相等运算符 === 在进行比较时不会做任何的类型转换。
换句话说,如果 a 和 b 属于不同的数据类型,那么 a === b 不会做任何的类型转换而立刻返回 false。
让我们试试:
alert( 0 === false ); // false,因为被比较值的数据类型不同
同样的,与“不相等”符号 != 类似,“严格不相等”表示为 !==。

对 null 和 undefined 进行比较
当使用 null 或 undefined 与其他值进行比较时,其返回结果常常出乎你的意料。
当使用严格相等 === 比较二者时
它们不相等,因为它们属于不同的类型。
alert( null === undefined ); // false

当使用非严格相等 == 比较二者时
JavaScript 存在一个特殊的规则,会判定它们相等。它们俩就像“一对恋人”,仅仅等于对方而不等于其他任何的值(只在非严格相等下成立)。
alert( null == undefined ); // true
当使用数学式或其他比较方法 < > <= >= 时:
null/undefined 会被转化为数字:null 被转化为 0,undefined 被转化为 NaN。

奇怪的结果:null vs 0
通过比较 null 和 0 可得:

alert( null > 0 ); // (1) false
alert( null == 0 ); // (2) false
alert( null >= 0 ); // (3) true
是的,上面的结果完全打破了你对数学的认识。在最后一行代码显示“null 大于等于 0”的情况下,前两行代码中一定会有一个是正确的,然而事实表明它们的结果都是 false。

为什么会出现这种反常结果,这是因为相等性检查 == 和普通比较符 > < >= <= 的代码逻辑是相互独立的。进行值的比较时,null 会被转化为数字,因此它被转化为了 0。这就是为什么(3)中 null >= 0 返回值是 true,(1)中 null > 0 返回值是 false。
另一方面,undefined 和 null 在相等性检查 == 中不会进行任何的类型转换,它们有自己独立的比较规则,所以除了它们之间互等外,不会等于任何其他的值。这就解释了为什么(2)中 null == 0 会返回 false。

特立独行的 undefined
undefined 不应该被与其他值进行比较:
alert( undefined > 0 ); // false (1)
alert( undefined < 0 ); // false (2)
alert( undefined == 0 ); // false (3)
为何它看起来如此厌恶 0?返回值都是 false!
原因如下:
(1) 和 (2) 都返回 false 是因为 undefined 在比较中被转换为了 NaN,而 NaN 是一个特殊的数值型值,它与任何值进行比较都会返回 false。
(3) 返回 false 是因为这是一个相等性检查,而 undefined 只与 null 相等,不会与其他值相等。

以下表达式的执行结果是?
5 > 4 → true
"apple" > "pineapple" → false
"2" > "12" → true
undefined == null → true
undefined === null → false
null == "\n0\n" → false
null === +"\n0\n" → false
结果的原因:
数字间比较大小,显然得 true。
按词典顺序比较,得 false。"a" 比 "p" 小。
与第 2 题同理,首位字符 "2" 大于 "1"。
null 只与 undefined 互等。
严格相等模式下,类型不同得 false。
与第 4 题同理,null 只与 undefined 相等。
不同类型严格不相等。

上一篇:JS 中判断空值 undefined 和 null


下一篇:自己编写的库文件在VS code上报错:undefined reference to ‘xxx’