基础知识
函数、数据类型、运算符。
代码引入
<script src="file.js"></script>
<script>
alert(1); //最好使用分号
</script>
// 这行注释独占一行
/* 两个消息的例子。
这是一个多行注释。 */
现代模式
脚本文件顶部声明user strict
即可开始现代模式
"use strict";
// 代码以现代模式工作
变量、常量、常数字
变量名称限制:
- 变量名称必须仅包含字母、数字、符号
$
和_
。 - 首字符必须非数字。
- 驼峰命名(建议)。
// 定义变量,并且赋值
let message = 'Hello!';
// 声明一个常数(不变)变量,可以使用 const 而非 let
const myBirthday = '18.04.1982';
// 使用大写形式声明常数(用于硬编码)
const COLOR_RED = "#F00";
数据类型
JavaScript 中有八种基本的数据类型。
- 七种原始数据类型(基本数据类型):
number
用于任何类型的数字:整数或浮点数,在±(253-1)
范围内的整数。bigint
用于任意长度的整数。string
用于字符串:一个字符串可以包含 0 个或多个字符,所以没有单独的单字符类型。boolean
用于true
和false
。null
用于未知的值 —— 只有一个null
值的独立类型。undefined
用于未定义的值 —— 只有一个undefined
值的独立类型。symbol
用于唯一的标识符。
- 以及一种非原始数据类型(复杂数据类型):
object
用于更复杂的数据结构。
// 没有错误, js是动态类型的编程语言
let message = "hello";
message = 123456;
// 对于number类型
// Infinity代表无限大
alert( 1 / 0 ); // Infinity
alert( Infinity ); // Infinity
// NaN,代表计算错误(粘性)
alert( "not a number" / 2 );
// 创建bigint类型的常量
const bigInt = 1234567890123456789012345678901234567890n;
// string类型的三种赋值方式
let str = "Hello";
let str2 = 'Single quotes are ok too';
let phrase = `can embed another ${str}`;
我们可以通过 typeof
运算符查看存储在变量中的数据类型。
- 通常用作
typeof x
,但typeof(x)
也可行。 - 以字符串的形式返回类型名称,例如
"string"
。 typeof null
会返回"object"
—— 这是 JavaScript 编程语言的一个错误,实际上它并不是一个object
。
typeof undefined // "undefined"
typeof 0 // "number"
typeof 10n // "bigint"
typeof true // "boolean"
typeof "foo" // "string"
typeof Symbol("id") // "symbol"
typeof Math // "object" (1)
typeof null // "object" (2)
typeof alert // "function" (3)
交互函数
这些方法都是模态的:它们暂停脚本的执行,并且不允许用户与该页面的其余部分进行交互,直到窗口被解除。
alert 模态框
alert("Hello");
prompt 文本模态框
result = prompt(title, [default]);
title
为窗口标题,[default]
为默认填充值, result
为接收值
// 建议始终 显式提供默认值
let test = prompt("Test", ''); // <-- 用于 IE 浏览器
confirm 确认模态框
result = confirm(question);
question
为弹窗内容, result
为接收值(true/false)
let isBoss = confirm("Are you the boss?");
alert( isBoss ); // 如果“确定”按钮被按下,则显示 true
上述所有方法共 有两个限制:
- 模态窗口的确切位置由浏览器决定。通常在页面中心。
- 窗口的确切外观也取决于浏览器。我们不能修改它。
类型转换
字符串转换 —— 转换发生在输出内容的时候,也可以通过 String(value) 进行显式转换。原始类型值的 string 类型转换通常是很明显的。
数字型转换 —— 转换发生在进行算术操作时,也可以通过 Number(value) 进行显式转换。
数字型转换遵循以下规则:
值 | 变成…… |
---|---|
undefined | NaN |
null | 0 |
true/false | 1/0 |
string | “按原样读取”字符串,两端的空白字符(空格、换行符 \n、制表符 \t 等)会被忽略。空字符串变成 0。转换出错则输出 NaN |
布尔型转换 —— 转换发生在进行逻辑操作时,也可以通过 Boolean(value) 进行显式转换。
布尔型转换遵循以下规则:
值 | 变成…… |
---|---|
0, null, undefined, NaN, "" false | false |
其他值 | true |
数学运算
支持以下数学运算:
加法 +
,
减法 -
,
乘法 *
,
除法 /
,
取余 %
,
求幂 **
.
+
应用于字符串连接
+
应用于数字转化
原地修改: +=
*=
自增/自减: ++
--
位运算符:
- 按位与 (
&
) - 按位或 (
|
) - 按位异或 (
^
) - 按位非 (
~
) - 左移 (
<<
) - 右移 (
>>
) - 无符号右移 (
>>>
)
alert( 8 % 3 ); // 2,8 除以 3 的余数
alert( 4 ** (1/2) ); // 2(1/2 次方与平方根相同)
alert( '1' + 2 ); // "12" 字符串拼接
// 运算元自动转化为数字
alert( 6 - '2' ); // 4,将 '2' 转换为数字
alert( '6' / '2' ); // 3,将两个运算元都转换为数字
// 加号应用于非数字的单个值时会将其转化为数字
let y = -2;
alert( +y ); // -2
alert( +true ); // 1
alert( +"" ); // 0
// 原地修改
let n = 2;
n *= 3 + 5;
alert( n ); // 16 (右边部分先被计算,等同于 n *= 8)
值的比较
我们知道,在数学中有很多用于比较大小的运算符。 在 JavaScript 中,它们的编写方式如下:
- 大于 / 小于:
a > b
,a < b
。 - 大于等于 / 小于等于:
a >= b
,a <= b
。 - 检查两个值的相等:
a == b
,请注意双等号==
表示相等性检查,而单等号a = b
表示赋值。 - 检查两个值不相等:不相等在数学中的符号是
≠
,但在 JavaScript 中写成a != b
。
字符串比较:按字符(母)逐个进行比较。
不同类型间的比较:
- 当对不同类型的值进行比较时,JavaScript 会首先将其转化为数字(number)再判定大小。
严格相等:===
在进行比较时不会做任何的类型转换。
对null和undefined进行比较:
- 使用
==
时它们相等 - 使用
===
时它们不等 - 使用数学式或
< > <= >=
时:null
被转化为0
,undefined
被转化为NaN
alert( 2 > 1 ); // true(正确)
alert( 2 == 1 ); // false(错误)
alert( 2 != 1 ); // true(正确)
alert( 'Z' > 'A' ); // true
alert( 'Glow' > 'Glee' ); // true
alert( 'Bee' > 'Be' ); // true
alert( '2' > 1 ); // true,字符串 '2' 会被转化为数字 2
alert( '01' == 1 ); // true,字符串 '01' 会被转化为数字 1
alert( true == 1 ); // true
alert( 0 === false ); // false,因为被比较值的数据类型不同
alert( null === undefined ); // false
alert( null == undefined ); // true
条件分支
if语句 :if
else if
else
let year = prompt('In which year was ECMAScript-2015 specification published?', '');
if (year < 2015) {
alert( 'Too early...' );
} else if (year > 2015) {
alert( 'Too late' );
} else {
alert( 'Exactly!' );
}
?
语句:
let accessAllowed = age > 18 ? true : false;
逻辑运算符
||(或)
1.操作布尔值(传统特性)
如果参与运算的任意一个参数为 true
,返回的结果就为 true
,否则返回 false
。
let hour = 12;
let isWeekend = true;
if (hour < 10 || hour > 18 || isWeekend) {
alert( 'The office is closed.' ); // 是周末
}
2.运算寻找第一个真值(Js特性)
或运算符 ||
做了如下的事情:
- 从左到右依次计算操作数。
- 处理每一个操作数时,都将其转化为布尔值。如果结果是
true
,就停止计算,返回这个操作数的初始值。 - 如果所有的操作数都被计算过(也就是,转换结果都是
false
),则返回最后一个操作数。
alert( 1 || 0 ); // 1(1 是真值)
alert( null || 1 ); // 1(1 是第一个真值)
alert( null || 0 || 1 ); // 1(第一个真值)
alert( undefined || null || 0 ); // 0(都是假值,返回最后一个值)
特殊用法: 1.获取变量列表或者表达式中的第一个真值。
alert( firstName || lastName || nickName || "Anonymous"); // SuperCoder
2.短路求值(Short-circuit evaluation)
true || alert("not printed");
false || alert("printed");
&&(与)
1.操作布尔值
当两个操作数都是真值时,与运算返回 true
,否则返回 false
alert( true && true ); // true
2.与运算寻找第一个假值
与运算 &&
做了如下的事:
- 从左到右依次计算操作数。
- 在处理每一个操作数时,都将其转化为布尔值。如果结果是
false
,就停止计算,并返回这个操作数的初始值。 - 如果所有的操作数都被计算过 (例如都是真值),则返回最后一个操作数。
// 如果第一个操作数是真值,
// 与运算返回第二个操作数:
alert( 1 && 0 ); // 0
alert( 1 && 5 ); // 5
// 如果第一个操作数是假值,
// 与运算将直接返回它。第二个操作数会被忽略
alert( null && 5 ); // null
alert( 0 && "no matter what" ); // 0
// 如果所有的值都是真值,最后一个值将会被返回
alert( 1 && 2 && 3 ); // 3,最后一个值
!(非)
逻辑非运算符接受一个参数,并按如下运作:
将操作数转化为布尔类型:true/false。 返回相反的值。
空值合并运算符 '??'
如果第一个参数不是 null/undefined,则 ?? 返回第一个参数。否则,返回第二个参数。
// 类似于
result = (a !== null && a !== undefined) ? a : b;
用来提供默认值:
let firstName = null;
let lastName = null;
let nickName = "Supercoder";
// 显示第一个已定义的值:
alert(firstName ?? lastName ?? nickName ?? "匿名"); // Supercoder
与||
比较:
- || 返回第一个 真 值。
- ?? 返回第一个 已定义的 值。
循环:while 和 for
循环体
while (condition) {
// 代码
// 所谓的“循环体”
}
do {
// 循环体
} while (condition);
for (begin; condition; step) {
// ……循环体……
}
跳出循环/继续迭代
通常条件为假时,循环会终止。但我们随时都可以使用 break 指令强制退出。
continue 指令是 break 的“轻量版”。它不会停掉整个循环。而是停止当前这一次迭代,并强制启动新一轮循环(如果条件允许的话)。
break/continue 标签
有时候我们需要一次从多层嵌套的循环中跳出来。
标签 是在循环之前带有冒号的标识符:
labelName: for (...) {
...
}
outer: for (let i = 0; i < 3; i++) {
for (let j = 0; j < 3; j++) {
let input = prompt(`Value at coords (${i},${j})`, '');
// 如果是空字符串或被取消,则中断并跳出这两个循环。
if (!input) break outer; // (*)
// 用得到的值做些事……
}
}
alert('Done!');
"switch" 语句
switch 语句可以替代多个 if 判断。
switch(x) {
case 'value1': // if (x === 'value1')
...
[break]
case 'value2': // if (x === 'value2')
...
[break]
default:
...
[break]
}
- 比较 x 值与第一个 case(也就是 value1)是否严格相等,然后比较第二个 case(value2)以此类推。
- 如果相等,switch 语句就执行相应 case 下的代码块,直到遇到最靠近的 break 语句(或者直到 switch 语句末尾)。
- 如果没有符合的 case,则执行 default 代码块(如果 default 存在)。 注意: 如果没有 break,程序将不经过任何检查就会继续执行下一个 case。 共享同一段代码的几个 case 分支可以被分为一组。 被比较的值必须是相同的类型才能进行匹配。
函数
函数声明
使用 函数声明 创建函数。
function name(parameter1, parameter2, ... parameterN) {
...body...
}
变量
1.局部变量 在函数中声明的变量只在该函数内部可见。 2.外部变量 函数也可以访问、修改外部变量。 如果在函数内部声明了同名变量,那么函数会 遮蔽 外部变量。
let userName = 'John';
function showMessage() {
userName = "Bob"; // (1) 改变外部变量
let message = 'Hello, ' + userName;
alert(message);
}
alert( userName ); // John 在函数调用之前
showMessage();
alert( userName ); // Bob,值被函数修改了
参数
我们可以通过参数将任意数据传递给函数。
默认值
如果一个函数被调用,但有参数(argument)未被提供,那么相应的值就会变成 undefined。
使用 =
为函数声明中的参数指定所谓的“默认”(如果对应参数的值未被传递则使用)值:
function showMessage(from, text = "no text given") {
alert( from + ": " + text );
}
showMessage("Ann"); // Ann: no text given
返回值
函数可以将一个值返回到调用代码中作为结果。 指令 return 可以在函数的任意位置。当执行到达时,函数停止,并将值返回给调用代码(分配给上述代码中的 result)。 空值的 return 或没有 return 的函数返回值为 undefined。
函数表达式
在 JavaScript 中,函数不是“神奇的语言结构”,而是一种特殊的值。
创建函数的语法 函数声明:
function sayHi() {
alert( "Hello" );
}
另一种创建函数的语法称为 函数表达式。 它 允许我们在任何表达式的中间创建一个新函数。
// 由于函数创建发生在赋值表达式的上下文中(在 `=` 的右侧),因此这是一个 **函数表达式**。
let sayHi = function() {
alert( "Hello" );
};
函数是一个值
重申一次:无论函数是如何创建的,函数都是一个值。上面的两个示例都。
我们还可以:
// 在 sayHi 变量中存储了一个函数
function sayHi() { // 创建
alert( "Hello" );
}
// 用 alert 显示这个变量的值
alert( sayHi ); // 显示函数代码
sayHi(); // Hello // 执行函数
let func = sayHi; // 复制
func(); // Hello // 运行复制的值(正常运行)
回调函数
function ask(question, yes, no) {
if (confirm(question)) yes()
else no();
}
ask
的两个参数值 showOk
和 showCancel
可以被称为 回调函数 或简称 回调。
function ask(question, yes, no) {
if (confirm(question)) yes()
else no();
}
ask(
"Do you agree?",
function() { alert("You agreed."); },
function() { alert("You canceled the execution."); }
);
这里直接在 ask(...) 调用内进行函数声明。这两个函数没有名字,所以叫 匿名函数。
函数声明 vs 函数表达式
定义:
- 函数声明:在主代码流中声明为单独的语句的函数。
- 函数表达式:在一个表达式中或另一个语法结构中创建的函数。
创建方式:
// 函数声明
function sum(a, b) {
return a + b;
}
// 函数表达式
let sum = function(a, b) {
return a + b;
};
创建时机: 1.函数声明:在函数声明被定义之前,它就可以被调用。 严格模式下,当一个函数声明在一个代码块内时,它在该代码块内的任何位置都是可见的。但在代码块外不可见。
如何让内部代码在外部可见? 使用函数表达式,将内部函数赋值给在外部已经声明的变量,并具有正确的可见性。
2.函数表达式:在代码执行到达时被创建,并且仅从那一刻起可用。 一旦代码执行到赋值表达式 let sum = function… 的右侧,此时就会开始创建该函数,并且可以从现在开始使用(分配,调用等)。
箭头函数
创建函数还有另外一种非常简单的语法,并且这种方法通常比函数表达式更好。 它被称为“箭头函数”,因为它看起来像这样:
let func = (arg1, arg2, ..., argN) => expression;
这里创建了一个函数 func
,它接受参数 arg1..argN
,然后使用参数对右侧的 expression
求值并返回其结果。
换句话说,它是下面这段代码的更短的版本:
let func = function(arg1, arg2, ..., argN) {
return expression;
};
举例:
let sum = (a, b) => a + b;
alert( sum(1, 2) ); // 3
// 只有一个参数,还可以省略掉参数外的圆括号
let double = n => n * 2;
// 如果没有参数,括号则是空的(但括号必须保留):
let sayHi = () => alert("Hello!");
多行的箭头函数:
let sum = (a, b) => { // 花括号表示开始一个多行函数
let result = a + b;
return result; // 如果使用了花括号,则需要显式“return”
};
alert( sum(1, 2) ); // 3