JS语法
区分大小写
完全区分大小写。如typeof是保留字不能作为函数名,但typeOF是一个完全有效的函数名。(如果你想搞同事可以借鉴一下)
标识符
既变量、函数、属性、参数名,有以下规则:
- 第一个字符必须是一个字母、下划线或$
- 剩下的其他字符可以是字母、下划线、$、数字
标识符中的字母可以是扩展 ASCII(Extended ASCII)中的字母,也可以是 Unicode 的字母字符,
如 À 和 Æ(同样是搞同事专用)。
ECMAScript标识符建议使用驼峰方式。
严格模式
严格模式是一种不同的JS解析和执行模型,ES3中的一些不规范写法在这种模式下会被处理,对于不安全的行为将抛出错误。在执行脚本头上加这一行:“use strict”(预处理指令)。也可以只在函数里声明。
function doSomething() {
"use strict";
// 函数体
}
关键字与保留字
规范中也描述了一组未来的保留字,同样不能用作标识符或属性名。虽然保留字在语言中没有特定
用途,但它们是保留给将来做关键字用的。
以下是 ECMA-262 第 6 版为将来保留的所有词汇。
始终保留:
- enum
严格模式下保留:
implements
package
public
interface
protected
static
let
private
模块代码中保留:
await
变量
var
全局提升
function test() {
message = "hi"; // 全局变量
}
test();
console.log(message); // "hi"
去掉之前的 var 操作符之后,message 就变成了全局变量。只要调用一次函数 test(),就会定义
这个变量,并且可以在函数外部访问到。在严格模式下,如果像这样给未声明的变量赋值,则会导致抛出 ReferenceError。
hoist提升
function foo() {
var age;
console.log(age);
age = 26;
}
foo(); // undefined
let
区别:
- let 跟 var 的作用差不多,但有着非常重要的区别。最明显的区别是,let 声明的范围是块作用域,
而 var 声明的范围是函数作用域。 - TDZ 暂时性死区
// name 会被提升
console.log(name); // undefined
var name = 'Matt';
// age 不会被提升
console.log(age); // ReferenceError:age 没有定义
let age = 26;
- var声明的全局变量挂到window对象上,let不会
- for里的定时器
const
const 的行为与 let 基本相同,唯一一个重要的区别是用它声明变量时必须同时初始化变量,且
尝试修改 const 声明的变量会导致运行时错误。
ECMS建议:不用var,const优先,let次之
数据类型
原始类型:
- undefind
- boolean
- null
- string
- symbol
- number
ECMS的类型是松散的,需要一种手段来确定任意变量,typeof 操作符就为此而生。 - undefind 未定义
- boolean 布尔
- string 字符串
- number 数字
- object 对象或者null
- function 函数
- symbol 符号
下面说几个typeof的注意点:
- typeof是一个操作符,不是函数,虽然不需要参数,但也可以使用参数
- typeof null → object [因为特殊值null被认为是一个空对象的引用]
严格讲,函数在ECMS中被认为是对象,并不代表一种数据类型。考虑到函数也有自己的特殊属性,故通过typeof作区分。
undefined类型
JS中一个比较特殊的存在。不是保留字符。
注意区分undefined和报错的区别:
let message; // 这个变量被声明了,只是值为 undefined
// age 没有声明
if (message) {
// 这个块不会执行
}
if (!message) {
// 这个块会执行
}
if (age) {
// 这里会报错
}
Null类型
Null 类型同样只有一个值,即特殊值 null。逻辑上讲,null 值表示一个空对象指针,这也是给
typeof 传一个 null 会返回"object"的原因:
let car = null;
console.log(typeof car); // "object"
故用途可以是:在定义将来要存值的对象时,初始化用xxx = null来定义。
关于null和undefined
有关系,但用途完全不一样
console.log(null == undefined); // true
这个‘==’的问题后面会细说
注意:null是假值
当检测null的时候,一定要明确自己想检测的是null字面值还是假值。
let message = null;
let age;
if (message) {
// 这个块不会执行
}
if (!message) {
// 这个块会执行
}
if (age) {
// 这个块不会执行
}
if (!age) {
// 这个块会执行
}
boolean类型
我们常用的if(xxx)实际上使用了布尔转换,既Boolean()。具体转化规则如下:
Number
JS中最有意思的数据类型。
Number使用IEEE 754格式表示整数和浮点值。
由于 JavaScript 保存数值的方式,实际中可能存在正零(+0)和负零(0)。正零和负零在所有情况下都被认为是等同的,这里特地说明一下。
浮点数
因为存储浮点值使用的内存空间是存储整数值的两倍,所以 ECMAScript 总是想方设法把值转换为
整数。在小数点后面没有数字的情况下,数值就会变成整数。类似地,如果数值本身就是整数,只是小
数点后面跟着 0(如 1.0),那它也会被转换为整数,如下例所示:
let floatNum1 = 1.; // 小数点后面没有数字,当成整数 1 处理
let floatNum2 = 10.0; // 小数点后面是零,当成整数 10 处理
对于非常大或非常小的数值,浮点值可以用科学记数法来表示。科学记数法用于表示一个应该乘以
10 的给定次幂的数值。ECMAScript 中科学记数法的格式要求是一个数值(整数或浮点数)后跟一个大
写或小写的字母 e,再加上一个要乘的 10 的多少次幂。比如:
let floatNum = 3.125e7; // 等于 31250000
ECMAScript 会将小数点后至少包含 6 个零的浮点值转换为科学记数法
浮点值的精确度最高可达 17 位小数
思考:0.1 + 0.2 != 0.3问题
取最大数值:Number.MAX_VALUE
取最小数值:Number.MIN_VALUE
确定一个值是不是有限大,使用isFinite()
let result = Number.MAX_VALUE + Number.MAX_VALUE;
console.log(isFinite(result)); // false
NaN
不是数值。
分子是0的时候:
console.log(0/0); // NaN
console.log(-0/+0); // NaN
分母是0的时候:
console.log(5/0); // Infinity
console.log(5/-0); // -Infinity
console.log(NaN == NaN); // false
js里的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
数值转换:【关于‘进制’问题,会抽出一篇文章来说】
3 个函数可以将非数值转换为数值:Number()、parseInt()和 parseFloat()。
Number()
布尔值:true→1 false→0
数值:直接返回
null→0
undefined→NaN
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 num = parseInt("0xAF", 16); // 175
事实上,如果提供了十六进制参数,那么字符串前面的"0x"可以省掉:
let num1 = parseInt("AF", 16); // 175
let num2 = parseInt("AF"); // NaN
在这个例子中,第一个转换是正确的,而第二个转换失败了。区别在于第一次传入了进制数作为参
数,告诉 parseInt()要解析的是一个十六进制字符串。而第二个转换检测到第一个字符就是非数值字
符,随即自动停止并返回 NaN。
通过第二个参数,可以极大扩展转换后获得的结果类型。比如:
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
Strring
String(字符串)数据类型表示零或多个 16 位 Unicode 字符序列。
特殊字符:
字符串长度length获取的长度为转译后的长度。
字符串拼接:
let lang = "Java";
lang = lang + "Script";
内部:整个过程首先会分配一个足够容纳 10 个字符的空间,然后填充上
“Java"和"Script”。最后销毁原始的字符串"Java"和字符串"Script",因为这两个字符串都没有用
了。
toString()方法可见于数值、布尔值、对象和字符串值。(没错,字符串值也有 toString()方法,
该方法只是简单地返回自身的一个副本。)null 和 undefined 值没有 toString()方法。
多数情况下,toString()不接收任何参数。不过,在对数值调用这个方法时,toString()可以
接收一个底数参数,即以什么底数来输出数值的字符串表示。默认情况下,toString()返回数值的十
进制字符串表示。而通过传入参数,可以得到数值的二进制、八进制、十六进制,或者其他任何有效基
数的字符串表示,比如:
let num = 10;
console.log(num.toString()); // "10"
console.log(num.toString(2)); // "1010"
console.log(num.toString(8)); // "12"
console.log(num.toString(10)); // "10"
console.log(num.toString(16)); // "a"
如果你不确定一个值是不是 null 或 undefined,可以使用 String()转型函数,它始终会返回表
示相应类型值的字符串。String()函数遵循如下规则。
如果值有 toString()方法,则调用该方法(不传参数)并返回结果。
如果值是 null,返回"null"。
如果值是 undefined,返回"undefined"。
下面看几个例子:
let value1 = 10;
let value2 = true;
let value3 = null;
let value4;
console.log(String(value1)); // "10"
console.log(String(value2)); // "true"
console.log(String(value3)); // "null"
console.log(String(value4)); // "undefined"
模板字符串
注:${}里的所有插入值都会用toString()强制转型为字符串
symbol类型
Object
太长了,这两个类型分到下个文章吧