语法
- 严格模式 use strict
在脚本开头加上这一行:”use strict”;
ECMAScript 3 的一些不规范写法在这种模式下会被处理,对于不安全的活动将抛出错误。
也可以单独指定一个函数在严格模式下执行,只要把这个预处理指令放到函数体开头即可:
function doSomething() {
"use strict";
// 函数体
}
语句
加分号也有助于在某些情况下提升性能,因为解析器会尝试在合适的位置补上分号以纠正语法错误。
let sum = a + b // 没有分号也有效,但不推荐
let diff = a - b; // 加分号有效,推荐
尽量使用代码块
// 有效,但容易导致错误,应该避免
if (test)
console.log(test);
// 推荐
if (test) {
console.log(test);
}
变量
var声明作用域
- 函数作用域
变量将在函数退出时被销毁
function test() {
var message = "hi"; // 局部变量
}
test();
console.log(message); // 出错!
在函数内部省略var操作符,可以创建一个全局变量
function test(){
message = "hi";
}
test();
console.log(message);
不推荐这么做,可能会造成全局变量污染
- 如果需要定义多个变量,中间用逗号隔开
var message = "hi",
found = false,
age = 29;
插入换行和空格缩进并不是必需的
- var声明变量提升
使用下面的代码不会报错
function foo() {
console.log(age);
var age = 26;
}
foo(); // undefined
相当于下面👇的代码
function foo() {
var age;
console.log(age);
age = 26;
}
foo(); // undefined
这就是所谓的“提升”,也就是把所有变量声明都拉到函数作用域的顶部
let声明
let 声明的范围是块作用域
var声明下👇if (true) {
var name = 'Matt';
console.log(name); // Matt
}
console.log(name); // Matt
let声明下👇 报错:没有定义
if (true) {
let age = 26;
console.log(age); // 26
}
console.log(age); // ReferenceError: age 没有定义
- 嵌套使用相同的标识符不会报错,而这是因为同一个块中没有声明重复
var name = 'Nicholas';
console.log(name); // 'Nicholas'
if (true) {
var name = 'Matt';
console.log(name); // 'Matt'
}
let age = 30;
console.log(age); // 30
if (true) {
let age = 26;
console.log(age); // 26
}
对声明冗余报错不会因混用let和var而受影响,这两个关键字声明的并不是不同类型的变量,它们只是指出变量在相关作用域如何存在。
var name;
let name; // SyntaxError
let age;
var age; // SyntaxError
暂时性死区
原因还是let声明的变量不会在作用域中被提升// name 会被提升
console.log(name); // undefined
var name = 'Matt';
// age 不会被提升
console.log(age); // ReferenceError:age 没有定义
let age = 26;
全局声明
使用 let 在全局作用域中声明的变量不会成为 window 对象的属性(var 声明的变量则会)var name = 'Matt';
console.log(window.name); // 'Matt'
let age = 26;
console.log(window.age); // undefined
条件声明
由于let的块级特性,不能依赖条件声明<script>
let name = 'Nicholas';
let age = 36;
</script>
<script>
// 假设脚本不确定页面中是否已经声明了同名变量
// 那它可以假设还没有声明过
if (typeof name === 'undefined') {
let name;
}
// name 被限制在 if {} 块的作用域内
// 因此这个赋值形同全局赋值
name = 'Matt';
try {
console.log(age); // 如果 age 没有声明过,则会报错
}
catch(error) {
let age;
}
// age 被限制在 catch {}块的作用域内
// 因此这个赋值形同全局赋值
age = 26;
</script>
4. for 循环中的 let 声明
使用 let 声明迭代变量时,JavaScript 引擎在后台会为每个迭代循环声明一个新的迭代变量。
for (let i = 0; i < 5; ++i) {
setTimeout(() => console.log(i), 0)
}
// 会输出 0、1、2、3、4
const 声明
const 的行为与 let 基本相同,唯一一个重要的区别是用它声明变量时必须同时初始化变量,且尝试修改 const 声明的变量会导致运行时错误。
数据类型
6中简单的:Undefined、Null、Boolean、Number、String 和 Symbol。
1种复杂的:Object(对象)
typeof 操作符
对一个值使用 typeof 操作符会返回下列字符串之一:
- “undefined”表示值未定义;
- “boolean”表示值为布尔值;
- “string”表示值为字符串;
- “number”表示值为数值;
- “object”表示值为对象(而不是函数)或 null; “function”表示值为函数;
- “symbol”表示值为符号。
let message = "some string";
console.log(typeof message); // "string"
console.log(typeof(message)); // "string"
console.log(typeof 95); // "number"
调用typeof null 返回的是”object”。这是因为特殊值 null 被认为是一个对空对象的引用。
Undefined 类型
不初始化的变量和未定义的变量进行typedof操作得出的答案是一样的都是undefined
定义的变量的时候为了区分开来,尽量赋值初始值
let message; // 这个变量被声明了,只是值为 undefined
// age 没有声明
if (message) {
// 这个块不会执行
}
if (!message) {
// 这个块会执行
}
if (age) {
// 这里会报错
}
永远不必显式地将变量值设置为 undefined
undefined 是一个假值
Null类型
null 值表示一个空对象指针,给typeof 传一个 null 会返回”object”
保存对象值的变量时,建议使用 null 来初始化
undefined 值是由 null 值派生而来的
console.log(null == undefined); // true
null 是一个假值
Boolean 类型
有两个字面值:true 和 false。
Boolean()转型函数:
let message = "Hello world!";
let messageAsBoolean = Boolean(message);
let message = "Hello world!";
if (message) {
console.log("Value is true");
}
Number 类型
Number 类型使用 IEEE 754 格式表示整数和浮点值
十进制
let intNum = 55; // 整数
八进制
必须以0开头
let octalNum1 = 070; // 八进制的 56
let octalNum2 = 079; // 无效的八进制值,当成 79 处理
let octalNum3 = 08; // 无效的八进制值,当成 8 处理
十六进制
必须以0x开头
前缀0x区分大小写,数字中的字母大小写均可
let hexNum1 = 0xA; // 十六进制 10
let hexNum2 = 0x1f; // 十六进制 31
正零和负零在所有情况下都被认为是等同的
1.浮点值
定义浮点值,必须有小数点
let floatNum1 = 1.1;
let floatNum2 = 0.1;
let floatNum3 = .1; // 有效,但不推荐
因为存储浮点值内存空间是存储整数值的两倍,所以ES想方设法把值转换为整数。
let floatNum1 = 1.; // 小数点后面没有数字,当成整数 1 处理
let floatNum2 = 10.0; // 小数点后面是零,当成整数 10 处理
浮点值的精确度最高可达 17 位小数,但计算时不够精确
if (a + b == 0.3) { // 别这么干!
console.log("You got 0.3.");
}
2.值的范围
- Number.MAX_VALUE表示最大数值
- Number.MIN_VALUE表示最小数值
如果超出了js的范围,则会得到一个Infinity(无穷)值,或者以-Infinity(负无穷大)
isFinite()函数可以确定一个值是不是有限大
let result = Number.MAX_VALUE + Number.MAX_VALUE;
console.log(isFinite(result)); // false
3.NaN
NaN是一个特殊的值,意思是“不是数值”(Not a Number)
用于表示本来要返回数值的操作失败了(而不是抛出错误)
- 任何涉及 NaN 的操作始终返回 NaN
- NaN 不等于包括 NaN 在内的任何值,也就是不能与任何值比较
console.log(NaN == NaN); // false
提供了一个isNaN()函数,判断某个数据是否“不是数值”
console.log(isNaN(NaN)); // true
console.log(isNaN(10)); // false,10 是数值
console.log(isNaN("10")); // false,可以转换为数值 10
console.log(isNaN("blue")); // true,不可以转换为数值
console.log(isNaN(true)); // false,可以转换为数值 1
数值转换
三个函数可以将非数值转换为数值
- Number()函数
- 布尔值,true 转换为 1,false 转换为 0。
- 数值,直接返回。
- null,返回 0。
- undefined,返回 NaN。
- 字符串,只有是数字的时候才返回,非数字返回NaN
- 空字符串返回0
let num1 = Number("Hello world!"); // NaN
let num2 = Number(""); // 0
let num3 = Number("000011"); // 11
let num4 = Number(true); // 1
- parseInt()函数
let num1 = parseInt("1234blue"); // 1234
let num2 = parseInt(""); // NaN
let num3 = parseInt("0xA"); // 10,解释为十六进制整数
let num4 = parseInt(22.5); // 22
let num5 = parseInt("70"); // 70,解释为十进制值
let num6 = parseInt("0xf"); // 15,解释为十六进制整数
可以用第二个参数规定传入的进制类型
let num1 = parseInt("10", 2); // 2,按二进制解析
let num2 = parseInt("10", 8); // 8,按八进制解析
let num3 = parseInt("10", 10); // 10,按十进制解析
let num4 = parseInt("10", 16); // 16,按十六进制解析
- parseFloat()函数
和上面差不多
let num1 = parseFloat("1234blue"); // 1234,按整数解析
let num2 = parseFloat("0xA"); // 0
let num3 = parseFloat("22.5"); // 22.5
let num4 = parseFloat("22.34.5"); // 22.34
let num5 = parseFloat("0908.5"); // 908.5
let num6 = parseFloat("3.125e7"); // 31250000