Skip to main content

基础知识

函数、数据类型、运算符。

代码引入

<script src="file.js"></script>
<script>
alert(1); //最好使用分号
</script>
// 这行注释独占一行
/* 两个消息的例子。
这是一个多行注释。 */

现代模式

脚本文件顶部声明user strict即可开始现代模式

"use strict";

// 代码以现代模式工作

变量、常量、常数字

变量名称限制:

  1. 变量名称必须仅包含字母、数字、符号 $ 和 _
  2. 首字符必须非数字。
  3. 驼峰命名(建议)。
// 定义变量,并且赋值
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

上述所有方法共有两个限制:

  1. 模态窗口的确切位置由浏览器决定。通常在页面中心。
  2. 窗口的确切外观也取决于浏览器。我们不能修改它。

类型转换

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

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

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

变成……
undefinedNaN
null0
true/false1/0
string“按原样读取”字符串,两端的空白字符(空格、换行符 \n、制表符 \t 等)会被忽略。空字符串变成 0。转换出错则输出 NaN

布尔型转换 —— 转换发生在进行逻辑操作时,也可以通过 Boolean(value) 进行显式转换。

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

变成……
0, null, undefined, NaN, "" falsefalse
其他值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 > ba < b
  • 大于等于 / 小于等于:a >= ba <= b
  • 检查两个值的相等:a == b,请注意双等号 == 表示相等性检查,而单等号 a = b 表示赋值。
  • 检查两个值不相等:不相等在数学中的符号是 ,但在 JavaScript 中写成 a != b

字符串比较:按字符(母)逐个进行比较。

不同类型间的比较:

  • 当对不同类型的值进行比较时,JavaScript 会首先将其转化为数字(number)再判定大小。

严格相等:=== 在进行比较时不会做任何的类型转换。

对null和undefined进行比较:

  • 使用==时它们相等
  • 使用===时它们不等
  • 使用数学式或 < > <= >= 时:null 被转化为 0undefined 被转化为 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 的两个参数值 showOkshowCancel 可以被称为 回调函数 或简称 回调。

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