JavaScript:ECMAScript
1. ECMA语法
1.1 区分大小写
变量、函数名、运算符以及其他一切东西都是区分大小写
test和Test是不同的
1.2 标识符
- 第一个字符必须是一个字母、下划线或美元符号,其他字符可以是这些加上数字,如$jason、dasi0227,_github
- 使用驼峰命名,如getNumber、dasiNetChina
- 关键字,保留字、true、false和null不能作为标识符
图片
1.3 注释
与C一样,当行注释用//,多行注释用/**/
1.4 语句
要求每行代码以;结尾
在控制语句中使用代码块{},哪怕只有一条语句!
1 | if (test) { |
1.5 严格模式
使用:在全局开头或函数开头加上一行"use strict",表示开启严格模式
意义:通过引入更严格的语法规则,可以帮助捕捉潜在的错误并防止一些不良的编程习惯,从而提高代码的安全性和性能
2. 变量
2.1 var
var的使用规则:
- 声明时,无需明确类型,也无需赋初值
1 | var test; |
- 声明后,可以改变保存的值,也可以改变值的类型
1 | var test = "dasi"; |
- 用同一个var语句定义的变量不必具有相同的类型
1 | var test1 = "dasi", test2 = 10; |
- 函数作用域:只在声明它的函数内部使用
1 | function example1() { |
- 声明提升(hoist):var变量的声明会自动提升到函数作用域顶部,但不会赋初值
1 | function example() { |
2.2 let
let的使用规则
- 块作用域,不允许在一个块内重复声明
1 | function example() { |
- 暂时性死区:let不会被提升,在声明之前的区域被称为暂时性死区,引用任何后面才声明的变量都会抛出
ReferenceError
1 | console.log(test1) // undefined |
let和for循环
- 仅限于循环块内部
1 | for (var i = 0; i < 5; ++i){ |
- 迭代变量独立性
1 | for (var i = 0; i < 3; i++) { |
2.3 const
使用规则
- 声明变量的同时必须初始化,并且不能修改变量的值
1 | const test = 1; |
- 不允许重复声明
1 | const test = 1; |
- 块作用域
1 | const test = 1; |
- const和对象:修改对象内部的属性不违反const规则
1 | const person = { |
实践过程中,推荐多使用const,然后是let,最后是var:可以使得变量有明确的作用域、声明位置和不变的值
3. 数据类型
3.1 undefined
情况:使用var或let声明一个变量但没有赋值,则变量的初始值就是undefined
1 | let message; |
不应该显式地给变量赋值为undefined,字面值undefined通常拿来与null作比较
3.2 null
情况:表示一个空对象指针,指示该变量尚未被分配实际的对象
- typeof:值是object而不是undefined
1 | let test = null; |
- 占位符
1 | let test = { |
undefined和null都是一个假值,做条件判断时要明确是要检测字面值,还是检测假值
3.3 boolean
布尔值:有两个字面值true和false
区分大小写:True和False不是布尔值,而是有效的标识符
不同于数值:true不是1,false不是0
Boolean()转型函数:控制语句中会执行自动转换,将其他值转换为布尔值进行判断
| 数据类型 | 转换为true | 转换为false |
|---|---|---|
| String | 非空字符串 | 空字符串"" |
| Number | 非零数值(包括无穷值) | 0和NaN |
| Object | 任意对象 | null |
| Undefined | 不存在 | undefined |
3.4 number
3.4.1 数值类型
表示形式
- 十进制:直接写出来即可
1 | let intNum = 55; |
- 八进制:第一个数字必须是0,然后接着是0-7
1 | let octalNum1 = 070; // 表示十进制数56 |
- 十六进制:前缀必须是0x,然后是0-9以及a-f(大小写均可)
1 | let hexNum1 = 0xA; // 表示十进制的10 |
- 浮点值:小数点后必须有一个数字
1 | let floatNum1 = 1.1; |
- 科学计数法:一个数值后跟字母e,再加上一个10的幂
1 | let floatNum = 3.125e7; // 相当于31250000 |
严格模式下,八进制的前缀0会判错,应该使用0o
永远不要测试某个特定的浮点值,这是计算机基于二进制计算产生的舍入误差导致的天生缺陷!
无穷值
- 最值:被保存在
Number.MIN_VALUE和Number.MAX_VALUE - 无穷值:如果某个计算的数值超过了最值,会被自动转换为正无穷值
Infinity或负无穷值-Infinity isFinite():用于判断一个值是否有限大
使用Number.NEGATIVE_INFINITY和Number.POSITIVE_INFINITY可以获得正负无穷值
NaN:不是数值(Not a Number),可以使用isNaN()判断参数是否不是数值
1 | console.log(0/0); // NaN |
在JavaScript中,出现错误计算不会中断代码执行,而是返回NaN值
3.4.2 数值转换
Number()- true:1
- false:0
- null:0
- undefined:NaN
- 字符串:如下
1 | let num0 = Number("JS"); // NaN |
parseInt():依次检测每个字符,直到字符串末尾,或碰到非数值字符
1 | let num1 = parseInt("123abc"); // 123 |
parseFloat():第一次出现小数点是有效的
1 | let num1 = parseFloat("123abc"); // 123 |
3.5 String
3.5.1 字符串
格式:使用双引号、单引号和反引号框起来的16位Unicode字符序列
如果要在字符串中使用特殊字符,如换行符、制表符、反斜杠、双引号等,需要在前面加上反斜杠符\
特点
- 不可变的(immutable):要修改字符串变量的值,必须销毁原始字符串,然后将包含新值的另一个字符串保存到变量
1 | let str = "JAVA"; |
length属性:返回字符串中16位字符的个数
如果字符是双字节字符,则length返回的不是准确的字符数
toString()和String()函数:将一个值转换为字符串
1 | let num = 1; |
不能对null和undefined使用toString(),但是可以使用String()
3.5.2 模版字面量
模版:必须使用反引号```,保留换行字符,可以跨行定义字符串,适用于编写HTML模版
1 | let pageHTML = ` |
模版字面量会保存反引号内的一切字符,因此使用缩进和空格是不一样的,要格外注意格式!
原始:可以使用String.raw函数,获取模版字面量的原始内容
1 | console.log(`\n`); // 换行 |
3.5.3 字符串插值
方法:在模版字面量中可以使用${}插值,所有值会自动使用toString()转换为字符串
1 | let value1 = 5; |
3.5.4 标签函数
tag function:自动将模版字面量拆分为模版数组和字符串数组
1 | function simpleTag(strings,...expressions) { |
- 注意参数前要加三个
. - 对于n个插值的模版字面量,传给标签函数的参数个数始终是n,字符串个数始终是n+1
- 如果模板字面量的开头或结尾是模板,那么strings数组的开头或结尾会是空字符串
3.6 Symbol
3.6.1 基本用法
Symbol:用于创建唯一的标识符,且每个符号实例都是不可变的,传递字符串参数作为符号描述
Symbol数据类型提供了一种创建唯一标识符的机制,非常适合用于避免属性名冲突和定义对象的特殊行为
Symbol():创建符号
1 | let sym0 = Symbol(); |
Symbol.for():创建全局符号注册表
1 | const globalSymbol1 = Symbol.for('globalKey'); |
Symbol.keyFor():查询全局注册表
1 | let sym1 = Symbol.for("global"); |
3.6.2 内置符号
用于暴露语言内部行为,开发者可以访问、模拟或重写这些行为
Symbol.iterator:定义对象默认迭代器,使对象可以使用for...of循环Symbol.aysnIterator:定义对象异步迭代器,使对象可以使用异步for-await-of循环Symbol.hasInstance:定义操作符instanceof,确定一个对象实例是否有原型Symbol.match:定义String.prototype.match()的行为,允许对象定义自己的匹配逻辑Symbol.search:定义String.prototype.search()的行为,允许对象定义如何搜索字符串Symbol.split:定义String.prototype.split()的行为,允许对象定义如何分割字符串Symbol.replace:定义String.prototype.replace()的行为,允许对象定义如何替换字符串
1 | /* 以Symbol.match为例子 */ |
3.7 Object
对象:存储一组键值对,包含属性和方法,通过new操作符后跟对象类型的名称来创建,可以在创建后随时添加、修改或删除属性和方法
1 | // 对象字面量 |
属性
constructor:指向对象的构造函数
1 | function Person(name) { |
Prototype:用于定义所有由该构造函数创建的对象共享的属性和方法
1 | function Person(name) { |
方法
hasOwnProperty(property):检查对象是否具有指定的自有属性
1 | const obj = { a: 1 }; |
isPropertyOf(object):检查当前对象是否在指定对象的原型链上
1 | function Person(name) { |
PropertyIsEnumerable(property):检查对象的指定属性是否可枚举
1 | const obj = { a: 1 }; |
toString():返回对象的字符串表示形式
1 | const obj1 = { |
valueOf():返回对象的原始值
1 | const obj = { |
4. 操作符
与其他语言相似,不做过多解释和例子
4.1 一元操作符
- 递增
++和递减--:分为前缀和后缀 - 一元加
+和一元减-:表示数值的符号
4.2 位操作符
- 按位非
~(实际上是对数值取反并减1) - 按位与
& - 按位或
| - 按位异或
^ - 左移
<<:按位补0,保留符号位 - 有符号右移
>> - 无符号右移
>>>
4.3 布尔操作符
- 逻辑非
! - 逻辑与
&& - 逻辑或
||
4.4 乘性操作符
- 乘法
* - 除法
/ - 取模
% - 指数
**
注意Infinity和NaN的情况,但一般情况下用不到,不做过多解释
4.5 加性操作符
- 加法
+ - 减法
-
4.6 关系操作符
- 小于
< - 大于
> - 小于等于
<= - 大于等于
>=
4.7 相等操作符
- 等于
==和不等于!=:自动转换操作数 - 全等
===和不全等!==:不转换操作数
图片
4.8 条件操作符
?::如果…就…否则…
4.9 赋值操作符
- 普通赋值
= - 复合赋值
*=,+=,-=,/=,<<=,>>=
4.10 逗号操作符
- 在一条语句中执行多个操作:
let num1 = 1, num2 = 2; - 返回表达式最后一个值:
let num = (1,2,3,4,5)
5. 语句
5.1 简单语句
这些语句是其他语言中都有的,简单描述
if (condition) {statement1} else {statement2}:如果就,否则就do {statement} while (expression):先执行一次,再测试循环条件while(expression) {statement}:先测试循环条件,再执行for (initialization; expression; post-loop-expression) {statement}:先初始化,然后检测循环条件,以及循环一次要执行的操作
5.2 for的拓展
for (property in expression) {statement}:用于遍历对象的可枚举属性for (preperty of expression) {statement}:用于遍历可迭代对象的元素(如数组、字符串、集合、映射等)
5.3 循环语句
break:立即退出循环continue:立即回到循环顶部执行label: {statement}:标签语句,通过在break和continue后面引用,使得嵌套循环更加清晰
5.4 with
with (expression) {statement}:将代码的作用域设置为特定的对象
1 | let num1 = object.name; |
with语句影响性能且难于调试,不建议使用
5.5 switch
每个case相当于如果expression === value,则会执行后面的语句,否则执行默认语句
注意,是全等,不执行自动类型转换
1 | switch (expression) { |
6. 函数
function Name(arg0, arg1) {statement}:JS的函数不需要指定返回值
函数相关将在后面讨论
