"use strict"
ES5 规范增加了新的语言特性并且修改了一些已经存在的特性。为了保证旧的功能能够使用,大部分的修改是默认不生效的。
你需要一个特殊的指令 —— "use strict" 来明确地激活这些特性。
- 请确保 "use strict" 出现在脚本的最顶部,否则严格模式可能无法启用。
- 只有注释可以出现在 "use strict" 的上面
- 没有类似于 "no use strict" 这样的指令可以使程序返回默认模式。(一旦进入了严格模式,就没有回头路了)
应该使用"use strict"模式吗
现代 JavaScript 支持 “classes” 和 “modules” —— 高级语言结构(本教程后续章节会讲到),它们会自动启用 use strict。
因此,如果我们使用它们,则无需添加 "use strict" 指令。因此,目前我们欢迎将 "use strict"; 写在脚本的顶部。稍后,当你的代码全都写在了 class 和 module 中时,你则可以将 "use strict";
这行代码省略掉
变量(var 而不是 let)
声明变量的三种方式
- var的问题
- var允许重新声明(如果是let就会报错)
var user = "Pete"; var user = "John"; // 这个 "var" 无效(因为变量已经声明过了) // …不会触发错误 alert(user); // John
- var 存在变量提升
声明会被提升,但是赋值不会。
- let - 变量
- const - 常量
- 硬编码时常量名应该大写
- 其他情况正常命名
数据类型
JavaScript 中有八种基本的数据类型(译注:前七种为基本数据类型,也称为原始类型,而 object 为复杂数据类型)。
- number 用于任何类型的数字:整数或浮点数,在 ± (2的53次方 - 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: 显示信息
- prompt: 显示信息要求用户输入文本。点击确定返回文本,点击取消或按下 Esc 键返回 null。
- 显示信息等待用户点击确定或取消。点击确定返回 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。
JS中特殊的运算符 - 空值合并运算符 '??'
- 空值合并运算符 ?? 提供了一种从列表中选择第一个“已定义的”值的简便方式。
它被用于为变量分配默认值:
// 当 height 的值为 null 或 undefined 时,将 height 的值设置为 100
height = height ?? 100;
?? 运算符的优先级非常低,仅略高于 ? 和 =,因此在表达式中使用它时请考虑添加括号。
如果没有明确添加括号,不能将其与 || 或 && 一起使用。
函数
函数声明方式如下所示:
function name(parameters, delimited, by, comma) {
/* code */
}
- 作为参数传递给函数的值,会被复制到函数的局部变量。
- 函数可以访问外部变量。但它只能从内到外起作用。函数外部的代码看不到函数内的局部变量。
- 函数可以返回值。如果没有返回值,则其返回的结果是 undefined。
为了使代码简洁易懂,建议在函数中主要使用局部变量和参数,而不是外部变量。
与不获取参数但将修改外部变量作为副作用的函数相比,获取参数、使用参数并返回结果的函数更容易理解。
函数命名:
- 函数名应该清楚地描述函数的功能。当我们在代码中看到一个函数调用时,一个好的函数名能够让我们马上知道这个函数的功能是什么,会返回什么。
- 一个函数是一个行为,所以函数名通常是动词。 目前有许多优秀的函数名前缀,如 create…、show…、get…、check… 等等。使用它们来提示函数的作用吧。
函数表达式
let sayHi = function() {
alert( "Hello" );
};
在这里,函数被创建并像其他赋值一样,被明确地分配给了一个变量。不管函数是被怎样定义的,都只是一个存储在变量 sayHi 中的值。
上面这两段示例代码的意思是一样的:“创建一个函数,并把它存进变量 sayHi”。
注意,最后一行代码并不会运行函数,因为 sayHi 后没有括号。在其他编程语言中,只要提到函数的名称都会导致函数的调用执行,但 JavaScript 可不是这样。
这就是一直不理解的地方, 其他语言是把函数的返回值赋值给变量, 在JS中就是简单的存储函数, 要执行就要带小括号()
总结: JS中函数是一个值, 所以我们可以把它当成值对待
function sayHi() { // (1) 创建
alert( "Hello" );
}
let func = sayHi; // (2) 复制
func(); // Hello // (3) 运行复制的值(正常运行)!
sayHi(); // Hello // 这里也能运行(为什么不行呢)
解释一下上段代码发生的细节:
- (1) 行声明创建了函数,并把它放入到变量 sayHi。
- (2) 行将 sayHi 复制到了变量 func。请注意:sayHi 后面没有括号。如果有括号,func = sayHi() 会把 sayHi() 的调用结果写进func,而不是 sayHi 函数 本身。
- 现在函数可以通过 sayHi() 和 func() 两种方式进行调用。
问题: 为什么这里末尾会有个分号?
你可能想知道,为什么函数表达式结尾有一个分号 ;,而函数声明没有:
function sayHi() {
// ...
}
let sayHi = function() {
// ...
};
答案很简单:
- 在代码块的结尾不需要加分号 ;,像 if { ... },for { },function f { } 等语法结构后面都不用加。
- 函数表达式是在语句内部的:let sayHi = ...;,作为一个值。它不是代码块而是一个赋值语句。不管值是什么,都建议在语句末尾添加分号 ;。所以这里的分号与函数表达式本身没有任何关系,它只是用于终止语句。
函数表达式 vs 函数声明(这两种方式的区别)
- 函数表达式是在代码执行到达时被创建,并且仅从那一刻起可用。
- 在函数声明被定义之前,它就可以被调用。
函数总结
函数是一个值, 函数声明的两种方式: 1, 函数声明 2, 函数表达式
- 函数是值。它们可以在代码的任何地方被分配,复制或声明。
- 如果函数在主代码流中被声明为单独的语句,则称为“函数声明”。
- 如果该函数是作为表达式的一部分创建的,则称其“函数表达式”。
- 在执行代码块之前,内部算法会先处理函数声明。所以函数声明在其被声明的代码块内的任何位置都是可见的。
- 函数表达式在执行流程到达时创建。
在大多数情况下,当我们需要声明一个函数时,最好使用函数声明,因为函数在被声明之前也是可见的。这使我们在代码组织方面更具灵活性,通常也会使得代码可读性更高。
所以,仅当函数声明不适合对应的任务时,才应使用函数表达式。在本章中,我们已经看到了几个例子,以后还会看到更多的例子。
箭头函数
创建函数还有另外一种非常简单的语法,并且这种方法通常比函数表达式更好
let func = (arg1, arg2, ...argN) => expression
let sum = (a, b) => a + b;
可以看到 (a, b) => a + b 表示一个函数接受两个名为 a 和 b 的参数。在执行时,它将对表达式 a + b 求值,并返回计算结果。
- 如果我们只有一个参数,还可以省略掉参数外的圆括号,使代码更短。
let double = n => n * 2;
// 差不多等同于:let double = function(n) { return n * 2 }
alert( double(3) ); // 6
- 如果没有参数,括号将是空的(但括号应该保留):
let sayHi = () => alert("Hello!");
sayHi()
多行的箭头函数
let sum = (a, b) => { // 花括号表示开始一个多行函数
let result = a + b;
return result; // 如果我们使用了花括号,那么我们需要一个显式的 “return”
};
alert( sum(1, 2) ); // 3
对于一行代码的函数来说,箭头函数是相当方便的。它具体有两种:
- 不带花括号:(...args) => expression — 右侧是一个表达式:函数计算表达式并返回其结果。
- 带花括号:(...args) => { body } — 花括号允许我们在函数中编写多个语句,但是我们需要显式地 return 来返回一些内容。