AI智能
改变未来

现代JavaScript 之JavaScript 基础知识(第一部分 第二章) 易错总结

(现代JavaScript 之JavaScript 基础知识 第一部分 第二章 易错总结)

2.1 Hello, world!

1. 现代 JavaScript 中已经不这样使用了。这些注释是用于不支持

<script>

标签的古老的浏览器隐藏 JavaScript 代码的。由于最近 15 年内发布的浏览器都没有这样的问题,因此这种注释能帮你辨认出一些老掉牙的代码。

<script type=…> <script language=…>

2. 一个单独的

&lt;script&gt;

标签不能同时有 src 特性和内部包裹的代码。

<script src=\"file.js\">alert(1); // 此内容会被忽略,因为设定了 src</script>

2.2 代码结构

1. 在大多数的编辑器中,一行代码可以使用<kbd>Ctrl+/</kbd> 热键进行单行注释,<kbd> Ctrl+Shift+/ </kbd>的热键可以进行多行注释
2. 不要在

/*...*/

内嵌套另一个

/*...*/

2.3 现代模式,"use strict"

1. 没有办法取消

\"use strict\"

没有类似于

\"no use strict\"

这样的指令可以使程序返回默认模式。一旦进入了严格模式,就没有回头路了。
2. 当你使用 开发者控制台 运行代码时,请注意它默认是不启动

\"use strict\"

的。你可以尝试搭配使用 <kbd>Shift+Enter</kbd> 按键去输入多行代码,然后将

\"use strict\"

放在代码最顶部。
3. 目前我们欢迎将 "use strict"; 写在脚本的顶部。稍后,当你的代码全都写在了 class 和 module 中时,你则可以将

\"use strict\"

; 这行代码省略掉。

2.4 变量

1. var 关键字与 let 大体 相同,也用来声明变量,但稍微有些不同,也有点“老派”。
2. 额外声明一个变量绝对是利大于弊的。现代的 JavaScript 压缩器和浏览器都能够很好地对代码进行优化,所以不会产生性能问题。为不同的值使用不同的变量可以帮助引擎对代码进行优化。

2.5 数据类型

8 种基本的数据类型

  • Number 类型
    特殊数值:Infinity-InfinityNaN,数学运算是安全的
  • BigInt 类型
    “number” 类型无法表示大于 (253-1)(即 9007199254740991),或小于 -(253-1) 的整数。这是其内部表示形式导致的技术限制。可以通过将 n 附加到整数字段的末尾来创建 BigInt 值。
  • String 类型
    反引号:
    let phrase = ``can embed another ${str}``;
  • Boolean 类型(逻辑类型)
    用于 true 和 false。
  • “null” 值
    JavaScript 中的 null 仅仅是一个代表“无”、“空”或“值未知”的特殊值。
  • “undefined” 值
    undefined 的含义是 未被赋值。如果一个变量已被声明,但未被赋值,那么它的值就是 undefined
  • object 类型
    用于更复杂的数据结构。
  • symbol 类型
    用于唯一的标识符。

typeof 运算符

  • 两种形式:typeof x 或者 typeof(x)。
  • typeof null 会返回 "object" —— 这是 JavaScript 编程语言的一个错误,实际上它并不是一个 object。

2.6 交互:alert、prompt 和 confirm

alert

alert(\"Hello\");

弹出的带有信息的小窗口被称为 模态窗
prompt

result = prompt(title, [default]);
title 显示给用户的文本default 可选的第二个参数,指定 input 框的初始值。(不是必须的)

confirm

result = confirm(question);

点击确定返回 true,点击取消返回 false

2.7 类型转换

字符串转换

字符串转换最明显。false 变成 "false",null 变成 "null" 等。
数字型转换

变成……
undefined NaN
null 0
true 和 false 1 and 0
string 去掉首尾空格后的纯数字字符串中含有的数字。如果剩余字符串为空,则转换结果为 0。否则,将会从剩余字符串中“读取”数字。当类型转换出现 error 时返回 NaN。

请注意 nullundefined 在这有点不同:null 变成数字 0undefined 变成 NaN
布尔型转换
转换规则如下:

  • 直观上为“空”的值(如 0、空字符串、null、undefined 和 NaN)将变为 false。
  • 其他值变成 true。
  • 对 "0" 和只有空格的字符串(比如:" ")进行布尔型转换时,输出结果为 true。

请注意:包含 0 的字符串 "0" 是 true

2.8 基础运算符,数学

数字转化,一元运算符 +

但是如果运算元不是数字,加号 + 则会将其转化为数字。

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

2.9 值的比较

一个有趣的现象

let a = 0;alert( Boolean(a) ); // falselet b = \"0\";alert( Boolean(b) ); // truealert(a == b); // true!

对 null 和 undefined 进行比较

当使用严格相等 === 比较二者时

它们不相等,因为它们属于不同的类型。

alert( null === undefined ); // false

当使用非严格相等 == 比较二者时

JavaScript 存在一个特殊的规则,会判定它们相等。它们俩就像“一对恋人”,仅仅等于对方而不等于其他任何的值(只在非严格相等下成立)。

alert( null == undefined ); // true

当使用数学式或其他比较方法 < > <= >= 时:

null/undefined 会被转化为数字:null 被转化为 0,undefined 被转化为 NaN。

alert( null > 0 );  // (1) falsealert( null == 0 ); // (2) falsealert( null >= 0 ); // (3) true

特立独行的 undefined

alert( undefined > 0 ); // false (1)alert( undefined < 0 ); // false (2)alert( undefined == 0 ); // false (3)

值的比较练习题

5 > 4 → true\"apple\" > \"pineapple\" → false\"2\" > \"12\" → trueundefined == null → trueundefined === null → falsenull == \"\\n0\\n\" → falsenull === +\"\\n0\\n\" → false

2.11 逻辑运算符

||(或)

result = value1 || value2 || value3;

一个或运算 || 的链,将返回第一个真值,如果不存在真值,就返回该链的最后一个值。

&&(与)

result = value1 && value2 && value3;

与运算返回第一个假值,如果没有假值就返回最后一个值。
与运算 && 的优先级比或运算 || 要高。

!(非)

两个非运算 !! 有时候用来将某个值转化为布尔类型:

alert( !!\"non-empty string\" ); // truealert( !!null ); // false

下面的代码将会输出什么?

alert( alert(1) || 2 || alert(3) );

答案:首先是 1,然后是 2.

与运算连接的 alerts 的结果是什么?

alert( alert(1) && alert(2) );

答案:1,然后 undefined。

或运算、与运算、或运算串联的结果

alert( null || 2 && 3 || 4 );

答案:3。

2.12 空值合并运算符 \’??\’

a ?? b 的结果是:

  • 如果 a 是已定义的,则结果为 a,
  • 如果 a 不是已定义的,则结果为 b。

重写 result = a ?? b

result = (a !== null && a !== undefined) ? a : b;

举例

let firstName = null;let lastName = null;let nickName = \"Supercoder\";// 显示第一个已定义的值:alert(firstName ?? lastName ?? nickName ?? \"Anonymous\"); // Supercoder

与 || 比较

它们之间重要的区别是:

  • || 返回第一个 值。
  • ?? 返回第一个 已定义的 值。

如果没有明确添加括号,不能将其与 || 或 && 一起使用。

2.13 循环:while 和 for

普通 break 只会打破内部循环
标签 是在循环之前带有冒号的标识符:

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; // (*)// 用得到的值做些事……}}

我们还可以将标签移至单独一行:

outer:for (let i = 0; i < 3; i++) { ... }

continue

指令也可以与标签一起使用。在这种情况下,执行跳转到标记循环的下一次迭代。

只有在循环内部才能调用 break/continue,并且标签必须位于指令上方的某个位置。

break label;  // 无法跳转到这个标签label: for (...)

易错题
以下两个循环的 alert 值是否相同?

前缀形式 ++i: 从 1 到 4

let i = 0;while (++i < 5) alert( i );

后缀形式 i++:从 1 到 5

let i = 0;while (i++ < 5) alert( i );

2.14 "switch" 语句

共享同一段代码的几个 case 分支可以被分为一组:

let a = 3;switch (a) {case 4:alert(\'Right!\');break;case 3: // (*) 下面这两个 case 被分在一组case 5:alert(\'Wrong!\');alert(\"Why don\'t you take a math class?\");break;default:alert(\'The result is strange. Really.\');}

2.15 函数

默认值

如果未提供参数,那么其默认值则是 undefined。

如果我们想在本示例中设定“默认”的 text,那么我们可以在 = 之后指定它:

function showMessage(from, text = \"no text given\") {alert( from + \": \" + text );}showMessage(\"Ann\"); // Ann: no text given

这里 "no text given" 是一个字符串,但它可以是更复杂的表达式,并且只会在缺少参数时才会被计算和分配。所以,这也是可能的:

function showMessage(from, text = anotherFunction()) {// anotherFunction() 仅在没有给定 text 时执行// 其运行结果将成为 text 的值}

后备的默认参数
我们可以拿它跟 undefined 做比较:

function showMessage(text) {if (text === undefined) {text = \'empty message\';}alert(text);}showMessage(); // empty message

我们可以使用 || 运算符:

// 如果 \"text\" 参数被省略或者被传入空字符串,则赋值为 \'empty\'function showMessage(text) {text = text || \'empty\';...}

现代 JavaScript 引擎支持 空值合并运算符 ??,当可能遇到其他假值时它更有优势,如 0 会被视为正常值不被合并:

// 如果没有传入 \"count\" 参数,则显示 \"unknown\"function showCount(count) {alert(count ?? \"unknown\");}showCount(0); // 0showCount(null); // unknownshowCount(); // unknown

空值的 return 或没有 return 的函数返回值为 undefined

函数命名

函数以 XX 开始……

  • "get…" —— 返回一个值,
  • "calc…" —— 计算某些内容,
  • "create…" —— 创建某些内容,
  • "check…" —— 检查某些内容并返回 boolean 值,等。

2.16 函数表达式

在 JavaScript 中,函数不是“神奇的语言结构”,而是一种特殊的值。

函数声明:

function sayHi() {alert( \"Hello\" );}

函数表达式:

let sayHi = function() {alert( \"Hello\" );};

我们可以复制函数到其他变量:

function sayHi() {   // (1) 创建alert( \"Hello\" );}let func = sayHi;    // (2) 复制func(); // Hello     // (3) 运行复制的值(正常运行)!sayHi(); // Hello    //     这里也能运行(为什么不行呢)

为什么这里末尾会有个分号?

function sayHi() {// ...}let sayHi = function() {// ...};
  • 在代码块的结尾不需要加分号 ;,像 if { … },for { },function f { } 等语法结构后面都不用加。
  • 函数表达式是在语句内部的:let sayHi = …;,作为一个值。它不是代码块而是一个赋值语句。不管值是什么,都建议在语句末尾添加分号 ;。所以这里的分号与函数表达式本身没有任何关系,它只是用于终止语句。

回调函数

function ask(question, yes, no) {if (confirm(question)) yes()else no();}function showOk() {alert( \"You agreed.\" );}function showCancel() {alert( \"You canceled the execution.\" );}// 用法:函数 showOk 和 showCancel 被作为参数传入到 askask(\"Do you agree?\", showOk, showCancel);

ask 的两个参数值 showOk 和 showCancel 可以被称为 回调函数 或简称 回调。

函数表达式 vs 函数声明

函数表达式是在代码执行到达时被创建,并且仅从那一刻起可用。

一旦代码执行到赋值表达式 let sum = function… 的右侧,此时就会开始创建该函数,并且可以从现在开始使用(分配,调用等)。

函数声明则不同。

在函数声明被定义之前,它就可以被调用。

一个全局函数声明对整个脚本来说都是可见的,无论它被写在这个脚本的哪个位置。

函数声明的另外一个特殊的功能是它们的块级作用域。

严格模式下,当一个函数声明在一个代码块内时,它在该代码块内的任何位置都是可见的。但在代码块外不可见。

如果我们使用函数声明,则以下代码无法像预期那样工作:

let age = prompt(\"What is your age?\", 18);// 有条件地声明一个函数if (age < 18) {function welcome() {alert(\"Hello!\");}} else {function welcome() {alert(\"Greetings!\");}}// ……稍后使用welcome(); // Error: welcome is not defined

正确的做法是使用函数表达式,并将 welcome 赋值给在 if 外声明的变量,并具有正确的可见性。

下面的代码可以如愿运行:

let age = prompt(\"What is your age?\", 18);let welcome;if (age < 18) {welcome = function() {alert(\"Hello!\");};} else {welcome = function() {alert(\"Greetings!\");};}welcome(); // 现在可以了

2.17 箭头函数,基础知识

单行箭头函数

let func = (arg1, arg2, ...argN) => expression

多行的箭头函数

let sum = (a, b) => {  // 花括号表示开始一个多行函数let result = a + b;return result; // 如果我们使用了花括号,那么我们需要一个显式的 “return”};alert( sum(1, 2) ); // 3

2.18 JavaScript 特性

typeof 运算符返回值的类型,但有两个例外:

typeof null == \"object\" // JavaScript 编程语言的设计错误typeof function(){} == \"function\" // 函数被特殊对待

值 null 和 undefined 是特殊的:它们只在 == 下相等,且不相等于其他任何值。

赞(0) 打赏
未经允许不得转载:爱站程序员基地 » 现代JavaScript 之JavaScript 基础知识(第一部分 第二章) 易错总结