第三章 语言基础

225 阅读7分钟

本章学习内容

1.语法
2.关键字与保留字
3.变量
4.数据类型
5.操作符
6.语句
7.函数

1. 语法

ECMAScript是松散型的语法。

1.1 区分大小写

var test 
var Test 
//可同时声明test、Test互不影响没有任何关系
var typeof = function(){} //报错typeof不能用于声明,因为它是个关键字
var Typeof = function(){} //没有问题,可以声明

1.2 标识符

简单讲就是变量、函数、属性、参数的名称,第一个字符必须是字母、下划线(_)、美元符号($),剩下的其他也可以是字母、下划线、美元符号、数字

var _data , $data , __proto__ , _data1 , $data2
//注意:保留字、关键字、true、false、null不能作为标识符

1.3 注释

//这是单行注释
/*这是
多行
注释*/

1.4 严格模式

ECMAScript5新增严格模式的概念,会把ECMAScript3的不规范写法处理,不安全的活动会抛出错误。

"use strict";
//这是对整个脚本启用严格模式,只需要在脚本头部添加"use strict"即可,它是一个预处理指令
function(){
"use strict";
//可以像这样单独指定一个函数在严格模式下执行。
}

1.5 语句

let sum = a + b  //没有分号也有效,但是解析器会自动确定语句在哪里结尾,不推荐这么写
let diff = a - b;//推荐保持这样的习惯
//代码块由 “{” 开始到 “}” 结束
if(test){ test = !test } //推荐,易读同时避免了不必要的错误
if(test) test != test    //有效,不推荐,容易导致错误

2. 关键字与保留字

ECMA-262保留了一组关键字,这些关键字都有特殊用途,例如控制语句的开始或结束、执行特定操作。保留字是保留给将来做关键字用的。

/*
ECAM-262第六版规定的所有关键字如下:
break、do、in、typeof、case、else、instanceof、var、catch、export、new、void、
class、extends、return、while、const、finally、super、 with、continue、for、
switch、yield、debugger、function、this、default、if、throw、
delete、import、try
*/
/*
ECAM-262第六版规定的所有保留字如下:
始终保留 : enum
严格模式:implements、package、public、interface、protected、static、let、private
模块代码:await
*/

3. 变量

什么是变量?用于保存任何类型的数据,变量只不过用于保存任意值的命名占位符。 有三个关键字是可以声明变量: var、const、let。其中只有var在ECMAScript任意版本中都可以使用,let、const只能在ECMAScript6及以上版本可以使用。

3.1 var关键字

var是一个操作符(关键字),后边是变量名(标识符)

 var message   //undefined

以上代码定义了一个名为message的变量,没有初始化的情况下,变量会保存一个特殊值undefined。

var message = 'hi';
message = 100; // 可行,但不推荐

以上代码定义了一个名为message的变量,并初始化一个字符串,值为hi,然后又改写为一个数值,值为100,虽然可行,但并不推荐改变变量的保存值的类型。

也可以同时定义多个变量,需要语句中间添加逗号

var message = "hi",
    found = false,
    age = 25; 

var声明的作用域

function test() {
  var message = "hi"; //函数内部变量——局部变量
}
test(); //执行完函数,就会销毁,所以下边的打印会报错
console.log(message); //报错
function test() {
   message = "hi"; //全局变量
}
test(); //执行完函数,就会销毁,但是message是全局变量所以打印成功
console.log(message); //hi

上边的代码在运行时是这样的

var message; //全局声明变量,未初始化,值为undefined
function test() {
   message = "hi"; //给全局变量赋值
};
test(); //执行完函数,就会销毁,但是message已经被赋值成功
console.log(message); //hi

注⚠️:上面省略var 去声明变量的方式不推荐,第一不好维护,第二在严格模式下这样的语法会报错。

var声明提升:使用var关键字声明的变量会自动提升到函数作用域的顶部。

function foo () {
    console.log(age); // undefined  为什么不报错误呢?
    var age = 25
};
foo();
//以上代码在运行时会解释成酱紫
function foo () {
    var age;
    console.log(age);
    age = 25
};
foo();

//这就是所谓的提升,把变量的声明提升到函数作用域的顶部
//当然反复的声明同一个变量也是没有问题的
function foo () {
    var age = 1;
    var age = 2;
    var age = 3;
    var age = 25;
    console.log(age); //25
};
foo();
//以上代码运行时解释成酱紫
function foo () {
    var age;
    age = 1;
    age = 2;
    age = 3;
    age = 25;
    console.log(age); //25   值被不断覆盖最后值为25
};
foo();

函数声明提升和变量声明提升都是提升到函数作用域的顶部之前我写过一个小实验,就是对这句话的解释。有不明白的同学可以跳过去看一哈,顺便指正一下我的不足

链接在这里请戳~

3.2 let声明

let是ECMAScript 6 新增的声明方式,与var作用一样,但是区别很大。 let声明的范围是块级作用域,var是函数作用域。 let声明不会提升且会造成暂时性死区。 let也不可以重复声明同一个变量

//----------------var声明-------------
if (true) {
    var name = "Jackson";
    console.log(name); // Jackson
};
console.log(name); //Jackson
//----------------let声明-------------
if (true) {
    let name = "Jackson";
    console.log(name); // Jackson
};
console.log(name); //ReferenceError: name 未定义

/*
因为let声明作用域是块级的,所name变量只存在于if语句中。
var的声明就不再解释了。
*/

暂时性死区

console.log(name); //undefined
var name = "Jackson";

console.log(age); //ReferenceError: age 没有定义
let age = "Jackson";  //let声明的age并不会提升
/*
解析代码时,JavaScript 引擎也会注意出现在块后面的 let 声明,只不过在此之前
不能以任何方式来引用未声明的变量。在 let 声明之前的执行瞬间
被称为“暂时性死区”(temporal dead zone),在此阶段引用任何后面才声明的变量都会抛出 ReferenceError。
*/

全局声明

//--------------------var声明------------------------
var name = "Jackson";
console.log(window.name);  //Jackson

//--------------------let声明------------------------
let age = 25;
console.log(window.age); //undefined
/*
let 声明仍然是在全局作用域中发生的,相应变量会在页面的生命周期内存续。因此,为了d
避免 SyntaxError,必须确保页面不会重复声明同一个变量。
*/

条件声明

/*
由于var声明会提升,Javascript引擎会自动将重复的声明在作用域顶部合并成一个声明。
因为let作用域是块级,所以不检查之前是否用let声明同名变量,也不可能存在没有声明的情况下声明变量
*/
<script>
    var name = "Jackson";
    let age = 25; //如果之前声明过age则这里会报错
</script>

//------------使用try/catch语句和typeof操作符------------------
<script>
    if (typeof name === 'undefined') {
        let name;
    };
                            name = "Jackson"; //当前name属于全局赋值,因为上边的name属于块级作用域
    
    
    
    try{
        console.log(age);  //没有声明过age的话,会报错
    }catch (error) {
        let age; //这里的age只存在于catch作用域中
    }
    age = 25; //这里的age也是全局赋值
    
</script>

注⚠️:不能使用 let 进行条件式声明是件好事,因为条件声明是一种反模式,它让程序变得更难理解。如果你发现自己在使用这个模式,那一定有更好的替代方式。

for循环中的let声明

//先看一下var在for循环中的表现
for (var i; i<5; i++) {
    setTimeout(()=>{ console.log(i) });   //5,5,5,5,5
};
console.log(i); // 5

之所以是以上结果,是因为在推出循环时,迭代变量(i)将导致退出循环的值保存下来(也就是5),之后才执行定时器的逻辑,打印出来自然是5个5,外部的打印也是5

//再来看看let在for循环中的表现
for (let i; i<5; i++) {
    setTimeout(()=>{ console.log(i) });   //1,2,3,4,5
};
console.log(i); // ReferenceError: i 没有定义

以上结果,是因为使用let声明迭代变量时,JavaScript引擎会在后台为每一个迭代变量声明一个新的迭代变量。每个定时器引用的i都是不同实例,所以打印出了我们期望的值。

3.3 const声明

const声明和let基本相同,很重要的区别就是,const声明变量时,必须初始化,且不可尝试修改变量,否则会报错。

const name ; // error
const name = "Jackson";
name = "Jack" //error
for (const i; i<5; i++){ console.log(i); }; //error const声明的变量不可修改
/*
但是迭代变量会自增,所以for循环应该使用let来声明迭代变量,
不过像创建一个不会被修改的for循环变量也是可以的,也就是说每次迭代只创建一个新变量。
*/
let i = 0;
for (const j=7; i<5; i++) {
    console.log(J);  //7,7,7,7,7
};
//这对for-in,for-of循环有很大帮助
for (const key in {a:1,b:2}){
    console.log(key);   // a, b
};
for(const value of [1,2,3,4,5]){
    console.log(value); // 1,2,3,4,5
};

3.4 声明风格及最佳实践

let和const声明方式,让js更加精确,声明的作用域、声明位置、值的稳定性。

  1. 不使用 var 有了 let 和 const,大多数开发者会发现自己不再需要 var 了。限制自己只使用 let 和 const 有助于提升代码质量,因为变量有了明确的作用域、声明位置,以及不变的值。

  2. const 优先,let 次之使用 const 声明可以让浏览器运行时强制保持变量不变,也可以让静态代码分析工具提前发现不合法的赋值操作。因此,很多开发者认为应该优先使用 const 来声明变量,只在提前知道未来会有修改时,再使用 let。这样可以让开发者更有信心地推断某些变量的值永远不会变,同时也能迅速发现因 意外赋值导致的非预期行为。

4. 数据类型

ECMAScript有六种简单数据类型(也叫原始类型):Undefined、Null、Boolean、Number、String、Symbol(ES6新增的)。还有一种复杂类型Object,Object是一种无序名值对的集合。

4.1 typeof操作符

typeof用来判断任意变量的数据类型,typeof是个操作符不是函数,但也可以接受参数进行判断

let message = "Hi~";
console.log(typeof message); // string
console.log(typeof (message)); // string
console.log(typeof Null); // object   

当typeof判断Null时返回的object书里是这样说明的,“这是因为特殊值Null被认为是一个控对象的引用”。JavaScript中不同对象在底层都表示为二进制,JavaScript 中每种数据类型使用3bit表示,会用二进制的前三位拿来做判断。null代表空指针,大多数平台中值为0x00,因此typeof判断时会返回"object"。

  • 000 表示Object类型的数据。
  • 001 表示Int类型的数据。
  • 010 表示Double类型的数据。
  • 100 表示String类型的数据。
  • 110 表示Boolean类型的数据。

4.2 Undefined类型

Undefined类型只有一个值,值为特殊值undefinef。当使用var或let声明变量,但未初始化时,会给变量赋值undefined。

注⚠️:永远不要显式的给变量赋值undefined,字面值undefined用于比较,在ECMAScript-262第三版之前是没有这个特殊值的,他的出现就是为了区分,明确控对象指针null和未初始化的变量

let name;
console.log(name); //undefined
console.log(age); //error (null)

console.log(typeof name); //undefined 
console.log(typeof age); //undefined 

无论是声明还是未声明,typeof 返回的都是字符串"undefined"。逻辑上讲这是对的,因为虽然 严格来讲这两个变量存在根本性差异,但它们都无法执行实际操作。所以建议在声明时对变量初始化。这样当typeof返回undefined时,就知道是因为没声明导致的。

4.3 Null类型

Null 类型同样只有一个值,即特殊值 null。逻辑上讲,null 值表示一个空对象指针,这也是给 typeof 传一个 null 会返回"object"的原因

let car = null;
console.log(typeof car); // object
/*
在定义将来要保存对象值的变量时,建议使用null来初始化,不要使用其他值。
这样只要检查这个变量的值是不是null就可以知道这个变量是否在后来被重新赋值
*/

所以当一个变量在将来会被赋值一个对象的情况下,推荐初始化时可以显式的设置为null。

4.4 Boolean类型

image.png

4.5 Number类型

最基本的数值字面量格式是十进制整数,整数也可以是八进制的活着十六进制字面量表示,在做数学操作是不论是什么进制,都会视为十进制树数值。

1.浮点值

let floatNum1 = 1.1;
let floatNum2 = 0.1;
let floatNum3 = .1;  //可行,但不推荐
let floatNum4 = 1.; //小数点后边没有值,当作1
let floatNum5 = 1.0;//小数点后边只有0,当作1
let floatNum1 = 3.125e7; // 31250000
/* 
对于非常大或非常小的数值,浮点值可以用科学记数法来表示。科学记数法用于表示一个应该乘以
10 的给定次幂的数值。ECMAScript 中科学记数法的格式要求是一个数值(整数或浮点数)后跟一个大
写或小写的字母 e,再加上一个要乘的 10 的多少次幂。
*/

/*
浮点值的精确度最高可达 17 位小数,但在算术计算中远不如整数精确。例如,0.1 加 0.2 得到的不
是 0.3,而是 0.300 000 000 000 000 04。由于这种微小的舍入错误,导致很难测试特定的浮点值。
*/
console.log((0.1*10+0.2*10))   //0.3

2.值的范围

由于内存的限制,ECMAScript 并不支持表示这个世界上的所有数值。ECMAScript 可以表示的最小 数值保存在 Number.MIN_VALUE 中,这个值在多数浏览器中是 5e-324;可以表示的最大数值保存在 Number.MAX_VALUE 中,这个值在多数浏览器中是 1.797 693 134 862 315 7e+308。如果某个计算得到的 数值结果超出了 JavaScript 可以表示的范围,那么这个数值会被自动转换为一个特殊的 Infinity(无 穷)值。任何无法表示的负数以-Infinity(负无穷大)表示,任何无法表示的正数以 Infinity(正无穷大)表示。如果计算返回正 Infinity 或负 Infinity,则该值将不能再进一步用于任何计算。这是因为 Infinity 没有可用于计算的数值表示形式。要确定一个值是不是有限大(即介于 JavaScript 能表示的 最小值和最大值之间),可以使用 isFinite()函数,如下所示:

let result = Number.MAX_VALUE + Number.MAX_VALUE;
console.log(isFinite(result)); // false

虽然超出有限数值范围的计算并不多见,但总归还是有可能的。因此在计算非常大或非常小的数值 时,有必要监测一下计算结果是否超出范围。

注⚠️: 使用 Number.NEGATIVE_INFINITY 和 Number.POSITIVE_INFINITY 也可以获 取正、负 Infinity。没错,这两个属性包含的值分别就是-Infinity 和 Infinity。

3.NaN(not a number)

一个特殊值,意思就是“不是个数”

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

4.数值转换

有三个函数可以将非数值转换成数值:Number()、parseInt()、parseFloat()

Number()方法的转换规则如下:
  • true转换为1,false为0
  • 数值直接返回
  • null为0
  • undefined为NaN
  • 如果字符串包含数字,或者加减符号则转换为十进制数值,忽略前面的零。
  • 如果字符串包含浮点值,返回浮点值,忽略前面的零。
  • 如果字符串包含十六进制,返回相对应的十进制数。
  • 如果字符串是空,返回0
  • 如果字符串是以上之外的情况则返回NaN
  • 对象调用valueOf(),并按照上述规则转换。如果结果为NaN,则调用toString(),以上述规则再转换
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,解释为十六进制整数

不同的数值格式很容易混淆,因此 parseInt()也接收第二个参数,用于指定底数(进制数)。如 果知道要解析的值是十六进制,那么可以传入 16 作为第二个参数,以便正确解析

let num = parseInt("0xAF", 16); // 175
//如果提供了十六进制参数,那么字符串前面的"0x"可以省掉
let num1 = parseInt("AF", 16); // 175
let num2 = parseInt("AF"); // 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,按十六进制解析

//因为不传底数参数相当于让 parseInt()自己决定如何解析,所以为避免解析出错,建议始终传给它第二个参数。
parseFloat()函数的工作方式跟 parseInt()函数类似,都是从位置 0 开始检测每个字符

parseFloat()函数的另一个不同之处在于,它始终忽略字符串开头的零。这个函数能识别所有浮点格式,以及十进制格式(开头的零始终被忽略)。十六进制数值始终会返回 0。因为parseFloat()只解析十进制值,因此不能指定底数。最后,如果字符串表示整数(没有小数点或者小数点后面只有一个零),则 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

4.6 String类型

String数据类型表示零或多个16位Unicode字符序列,字符串可以使用""、''、``,开头的引号必须和结尾的一致,否则报错。

let name = 'Jackson'; //ok
let name = "Jackson"; //ok
let name = `Jackson`; //ok
let name = 'Jackson"; //error

1.字符字面量

字符串数据类型包含一些用于表示非打印字符或有其他用途

\n  //换行
\t  //制表
\b  //退格
\r  //回车
\f  //换页
\\  //反斜杠(\)
\'  //单引号,可以在字符串以单引号标示时使用
\"  //双引号
\`  // 反引号
\xnn  //以十六进制编码nn表示的字符串
\unnnn  //以十六进制编码nnnn表示的字符串

2.字符串的特点

ECMAScript 中的字符串是不可变的(immutable),意思是一旦创建,它们的值就不能变了。要修改某个变量中的字符串值,必须先销毁原始的字符串,然后将包含新值的另一个字符串保存到该变量

3.转换为字符串 两种方式,第一种toString(),可以将数值、布尔值、对象、字符串值转换,其中字符串使用toString()是创建一个自身的副本,null和undefined没有toString()方法,toString()可接收一个底数作为参数,将数值转换成相对应的进制。第二种就是+''的方式啦

4.模版字符串和插值(略,我懒)

4.7 Symbol类型

Symbol(符号)是 ECMAScript 6 新增的数据类型。符号是原始值,且符号实例是唯一、不可变的。 符号的用途是确保对象属性使用唯一标识符,不会发生属性冲突的危险。 尽管听起来跟私有属性有点类似,但符号并不是为了提供私有属性的行为才增加的(尤其是因为 Object API 提供了方法,可以更方便地发现符号属性)。相反,符号就是用来创建唯一记号,进而用作非 字符串形式的对象属性。

1.符号的基本用法

let sym = Symbol();
console.log(typeof sym); // symbol

let symbolOne = Symbol();
let symbolTwo = Symbol();
console.log(symbolOne == symbolTwo); // false
console.log(symbolOne); // Symbol()

let fooSymbol = Symbol('foo');
let otherFooSymbol = Symbol('foo');
console.log(fooSymbol == otherFooSymbol); // false
console.log(fooSymbol); // Symbol('foo')

// symbol是不可以用new关键字,这样是为了避免创建符号包装对象。如果想使用符号包装对象,可以使用Object()

let mySymbol = Symbol();
let newSymbol = Object(mySymbol)
console.log(typeof newSymbol); // Object

2.使用全局符号注册表(symbol for)

创建时会检查全局是否寻在有这个key的symbol。如果存在就直接返回这个symbol,如果不存在就会原地创建并注册全局

let id = Symbol.for("id");
let obj = {
    [id] = '12345';
};
console.log(obj[id]); // "12345"
console.log(id); // Symbol(id)

let id2 = Symbol.for('id');
console.log(id === id2); // true   symbol.for对key的重用
console.log(obj[id2]); // '12345'
console.log(id2); // Symbol(id)

//我们还可以使用Symbol.keyFor来查询注册表
console.log(Symbol.keyFor('id')); // id
console.log(Symbol.keyFor('id2')); // id
console.log(Symbol.keyFor('id3')); // undefined  没注册的查不到

3.使用符号作为属性

let s1 = Symbol('foo'),
s2 = Symbol('bar'),

let o = {
    [s1]: 'foo val';
};
console.log(o); // { Symbol(foo): 'foo val' }

Object.defineProperty(o,s2,{value:'bar val'});
console.log(o); // { Symbol(foo): 'foo val', Symbol(bar): 'baz bar' }

//Object.getOwnPropertyNames()返回的是对象实例的常规属性数组
//Object.getOwnPropertySymbols()返回的是对象实例的符号属性数组
//Object.getOwnPropertyDescriptors()返回的是两种类型的属性描述的对象
//Reflect.ownKeys()返回的是两种类型的键
let s1 = Symbol('foo'),
s2 = Symbol('bar');
let o = {
    [s1]: 'foo val',
    [s2]: 'bar val',
    baz: 'baz val',
    qux: 'qux val'
};
console.log(Object.getOwnPropertySymbols(o));// [Symbol(foo), Symbol(bar)]
console.log(Object.getOwnPropertyNames(o));// ["baz", "qux"]
console.log(Object.getOwnPropertyDescriptors(o));
// {baz: {...}, qux: {...}, Symbol(foo): {...}, Symbol(bar): {...}}
console.log(Reflect.ownKeys(o));// ["baz", "qux", Symbol(foo), Symbol(bar)]

4.其他 API(略,里边的API几乎没有用到过,所以日后研究一番再补回来)

4.8 Object类型

通过new操作符创建对象

let o = new Object() 
//每个对象实例都有以下属性和方法:

//1.constructor属性,返回当前实例的构造函数
console.log(o.constructor); //ƒ Object() { [native code] } 

//2.hasOwnProperty(propertyName)判断当前实例存不存在指定属性或方法
o.name = "Jackson"
console.log(o.hasOwnProperty("name")) //true
 
//3.isPrototypeOf(object) 用于判断当前对象是否是另一个对象的原型(看完第八章回来补哦)

//4.propertyIsEnumerable(propertyName) 判断属性是否可以使用

//5.toLocaleString() 返回对象的字符串表达式,该字符串反应对象在本地化执行环境
console.log(o.toLocaleString()); // [object Object]

//6.toString() 返回对象字符串表达式
console.log(o.toString());  // [object Object]
//7.valueOf() 返回对象对应的字符串、数值、布尔值的表达式。通常与toString()返回值相同

5. 操作符

5.1 一元操作符

只操作一个值的操作符叫一元操作符

  1. 递增、递减操作符
前缀递增递减

let age = 29;
++age;           //30
//相当于
let age = 29;
age = age + 1;   //30

let age = 29;
--age;  //28
//在执行操作后,变量age的值变成了28
let age = 29;
let anotherAge = --age + 2;
console.log(age);        // 28
console.log(anotherAge); // 30
//前缀递增递减在语句中的优先级是相等的,因此会从左到右依次求职

后缀递增递减
//和前缀的区别就是执行完语句后求的值才是变化的结果
let num1 = 2;
let num2 = 20;
let num3 = num1-- + num2; //22
let num4 = num1 + num2;   //21

还可以对其他类型的值进行操作
let s1 = '2';
let s2 = 'z';
let b = false;
let f = 1.1;
let o = {
    valueOf(){
        return -1;
    }
 };
s1++;   //变成数值3
s2++;   //变成NaN
b++;    //变成数值1
f--;    //变成0.10000000000009(因为浮点值不精确)
o--;    //变成-2
  1. 一元加减
一元加减符号在变量前,+在变量前并没有什么改变。-号就跟数学一样,非数值类型的先转换成数值类型

5.2 位操作符(我不知该如何描述,待我整透透了,再来)

5.3 布尔操作符

直接看代码吧

// &&  ||  !
// 与   或  非

let a = true;
console.log(!a); // false

let b = false;
console.log( a || b ); //true
console.log( !a || b ); //false

let c = true;
console.log(a && c ); //true
console.log(!a && c); //false
console.log(!a && b); //false

5.3 其他操作符

乘性操作符、指数操作符、关系操作符与数学课上的基本一致 不是数值类型的则进行转换。

//主要说明一下 =  ==  === 的区别
// = 就是赋值操作
// == 等于
// === 全等于(会比较类型)
let a = '1';
let b = 1;
console.log(a == b); //true
console.log(a === b); //false因为a是字符串1
console.log(a != b); //false
console.log(a !== b); //true

//其他赋值操作

//乘后赋值(*=)
//除后赋值(/=)
//取模后赋值(%=)
//加后赋值(+=)
//减后赋值(-=)
//左移后赋值(<<=)
//右移后赋值(>>=)
//无符号右移后赋值(>>>=)

//逗号操作符——可同时声明多个变量
let a = 1,b = 2,c = 3;

6. 语句

7. 函数

阿啊阿啊阿啊西吧,最近太忙了。时间来不及了。我选择停更。等明年稳定了继续