JavaScript学习-3-语言基础

245 阅读11分钟

第三章-语言基础

3.1 语法

3.1.1 区分大小写

ECMAScript中一切都区分大小写

3.1.2 标识符

  • 第一个字母表示是一个字母、下划线(_)或美元符号($)
  • 剩下的其它字母可以是字母、下划线、美元符号或数字

最佳实践:驼峰标识

3.1.3 注释

  • 单行注释
// 这是注释
  • 多行注释
/**
 注释1
 注释2
*/

3.1.4 严格模式

"use strict"

可以在脚本的开头声明严格模式,也可以在函数的开头声明严格模式;

3.1.5 语句

最佳实践:语句最后添加分号

  • 加分号便于通过删除空行来压缩代码
  • 提升性能:解析器会尝试在合适的位置补上分号以纠正语法错误

3.2 关键字和保留字

3.3 变量

3.3.1 var关键字

声明变量不初始化的情况下,变量为undefined

3.3.1.1 var声明作用域

使用var操作符定义的变量会变成包含它的函数的局部变量

function test() {
  var message = 'hi'; // 局部变量
}
test();
console.log(message); // error:变量为定义

如果变量声明的时候省略了var,变量就会提升为全局变量,但是不推荐这么做!

function test() {
  message = 'hi'; // 全局变量
}
test();
console.log(message); // 'hi'

3.3.1.2 var声明提升

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

function foo() {
  console.log(age);
  var age = 26;
}
foo(); // undefined

上面代码相当于:

function foo() {
  var age;
  console.log(age);
  age = 26;
}
foo(); // undefined

3.3.2 let声明

let和var的重要区别

  • let声明的范围是块作用域,而var声明的范围是函数作用域

    if (true) {
      var name = 'zzz';
      console.log(name); // zzz
    }
    console.log(name); // zzz var不具备块作用域,所以name相当于全局变量
    
    if (true) {
      let name = 'zzz';
      console.log(name); // zzz
    }
    console.log(name); // ReferenceError: name没有定义 let是具有块级作用域的,只能在if块中访问name
    
  • let声明的变量同一个作用域中不能多次声明

    var name;
    var name; // 这是ok的
    
    let age;
    let age; // syntaxError: age已经声明过
    
  • 暂时性死区:let声明的变量不会在作用域中提升

    console.log(name); // undefined
    var name = 'aaa';
    
    console.log(age); // ReferenceError: age没有定义 let声明的变量不能在声明之前使用
    let age = 18;
    
  • 全局声明:var声明在全局作用域中的变量会成为window对象的属性,而let不会

    var name = 'zzz';
    console.log(window.name); // zzz
    
    let age = 18;
    console.log(window.age); // undefined
    
  • for循环中的let、var

    for (var i = 0; i < 5; i++) {
    	// do something
    }
    console.log(i); // 5 var没有块作用域,相当于声明了一个全局变量
    
    for (let i = 0; i < 5; i++) {
    	// do something
    }
    console.log(i); // refrenceError: i没有定义 let具有块级作用域
    
    for (var i = 0; i < 5; i++) {
    	setTimeout(() => {
    		console.log(i); // 5 5 5 5 5  所有的i都是同一个变量
    	}, 0);
    }
    
    for (let i = 0; i < 5; i++) {
    	setTimeout(() => {
    		console.log(i); 
        // 0 1 2 3 4  每个循环迭代会声明一个新的迭代变量,每个setTimeout引用的都是不同的变量实例
    	}, 0);
    }
    类似于
    {
      let i = 0; 
      setTimeout(() => {
        console.log(i);
      })
    }
    {
      let i = 1; 
      setTimeout(() => {
        console.log(i);
      })
    }
    ...
    {
      let i = 4; 
      setTimeout(() => {
        console.log(i);
      })
    }
    

3.3.3 const声明

  • const声明的变量,声明时必须同时初始化,并且不能修改(这里不能修改指的是不能修改变量所在的内存地址,如果是一个对象,是可以修改对象内部的属性的)
  • const声明的变量,同一作用域下不允许重复声明,并且const的作用域也是块

3.3.4 声明风格及最佳实践

声明变量使用优先级: const > let > var,尽量不使用var

3.4 数据类型

  • 6种基本数据类型:Undefined、Null、Boolean、Number、String、Symbol
  • 1种复杂数据类型: Object

3.4.1 typeof操作符

typeof操作符会返回下列字符串之一(首字母要小写):

  • undefined: 值未定义
  • boolean: 布尔值
  • string:字符串
  • number:数值
  • object: 对象或者null
  • function: 函数
  • symbol: 符号

3.4.2 Undefined类型

  • 未声明量typeof会返回undefined,未定义的变量typeof也会返回undefined

    let name;
    
    console.log(typeof name); // undefined 未定义
    console.log(typeof age); // undefined 未声明
    

3.4.3 Null类型

  • typeof null 返回Object
  • null == undefined null !== undefined

3.4.4 Boolean类型

数据类型转换为TRUE转换为FALSE
BooleanTrueFalse
String非空字符串""
Number非0数值(包括无穷值)0,NaN
Object任意对象Null
undefined不存在undefined

3.4.5 Number类型

  • 八进制(严格模式下八进制无效,不推荐使用八进制)

    let intNum1 = 070; // 56 第一个数字必须是0
    let intNum2 = 079; // 79 如果字面量中包含的数字超出了8,则会忽略前导0,当做十进制
    let intNum3 = 08// 8
    
  • 十六进制

    前缀:0x

3.4.5.1 浮点值

  • 小数点后面没有数字或者小数点后面全是0,会当做整数处理

    let floatNum1 = 1.; // 1
    let floatNum2 = 10.0; // 10
    
  • 浮点数的精确度最高可达17位小数,会带来浮点数判断问题

    0.1 + 0.2 == 0.3 // false
    

3.4.5.2 值的范围

  • 最大值:Number.MIN_VALUE

  • 最小值:Number.MIN_VALUE

  • 无穷大: 正(Infinity) 负(-Infinity)

  • 判断是否为有限大:isFinite()函数

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

3.4.5.3 NAN 非数值

  • 0、+0、-0相除会返回NaN

    console.log(0/0); // NaN
    console.log(-0/+0); // NaN
    
    console.log(5 / 0); // Infinity
    console.log(5 / -0); // -Infinity
    
  • 任何涉及NaN的操作始终返回NaN

  • NaN不等于任何值,包括自身

    console.log(NaN == NaN); // false
    
  • isNaN()函数是否为NaN,如果可以参数可以转换为数值,返回false,否则返回true

3.4.5.4 数值转换

非数值转换为数值的三种方法:Number()、parseInt()、parseFloat()

  1. Number()函数

    数据类型转换规则
    布尔值true->1 false->0
    数值直接返回
    null0
    undefinedNaN
    字符串1. 如果字符串包含数值字符,包括带+号,-号的情况,则转换为一个十进制数 2. 如果字符串包含有效地浮点值格式,如“1.1”,则会转换为相应的浮点值,会忽略前导0 3. 如果字符串包含有效地十六进制格式,如“0xf”,则会转换十进制整数值 4. 如果是空字符串,则返回0 5. 如果字符串包含除上述情况之外的其他字符,则返回NaN
    对象1. 先调用对象的valueOf()方法,并且按照上述(上述五种)规则转换返回的值 2. 如果转换的结果是NaN,则调用toString()方法,再按照字符串的规则转换
  2. parseInt()函数-将字符串转换为数值

    • 字符串最前面的空格会被忽略,从第一个非空格字符开始转换
    • 如果第一个字符不是数值字符、加号或者减号,立即返回NaN(空串会返回NaN)
    • 如果第一个字符是数值字符、加号或者减号,则会依次检测每个字符,直到字符串末尾或者碰到非数值字符,比如“1234blue”会转换为1234, “22.5”会被转换为22
    • 以0x开头的会以16进制解析为对应的十进制
    • parseInt接收第二个参数,用于指定进制数
    let num1 = parseInt("1234blue");  // 1234
    let num2 = parseInt(""); 					// NaN
    let num3 = parseInt("0xA");       // 10,解释为十六进制整数
    let num4 = parseInt("22.5");				// 22
    
    let num5 = parseInt('0xAF', 16); // 175
    let num6 = parseInt('AF', 16); // 175
    let num7 = parseInt('AF'); // NaN 没有指定进制数
    
  3. parseFloat()函数

    • parseFloat工作方式与parseInt函数类似,都是从位置0开始检测每个字符,直到解析到字符串的末尾或者解析到一个无效的浮点数值字符为止
    • 第一次出现的小数点是有效的,但第二次出现的小数点就无效了,剩余字符将会被忽略,例如22.34.5将会被解析为22.34
    • 会始终忽略字符串开头的0,并且只解析十进制值
    • 如果字符串表示整数(没有小数点或者小数点后面只有一个0),则会返回整数
    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");   // 321250000
    

3.4.6 String类型

3.4.6.1 字符字面量

3.4.6.2 字符串的特点

  • 不可变:要修改某个变量中的字符串值,必须先销毁原始的字符串,然后将包含新值的另一个字符串保存到该变量

3.4.6.3 转换为字符串

  • toString(),该方法可以接收一个底数参数,以什么底数来输出数值的字符串表示(2,8,10,16)

  • toString()方法对null和undefined无效,如果不确定值是不是null或者undefined,则可以使用String()转型函数

    • 如果值有toString()方法,则调用该方法并返回结果
    • 如果是null,则返回'null'
    • 如果是undefined,则返回'undefined'
  • 用加号操作符也可以转换字符串a + ''

3.4.6.4 模板字面量

let value = `aaaaaa`;
  • 反引号
  • 模板字面量会保持反引号内部的空格,空格也算字符,所以字符串长度会跟预想的不一样
  • 模板字面量中也有可能会包含换行符

3.4.6.5 字符串插值

let value = 5;
let exponent = 'second';
let res = `${value} to the ${exponent} power is ${value*value}`

3.4.6.6 模板字面量标签函数

3.4.6.7 原始字符串

3.4.7 Symbol(符号)类型

  • 符号是基本类型
  • 符号实例是唯一的,不可变的
  • 符号的用途是确保对象属性使用唯一标识符,不会发生属性冲突的危险

3.4.7.1 符号的基本用法

typeof 返回 symbol

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

可以传入一个字符串参数,但是这个字符串参数与符号定义或标识完全无关

let sym1 = Symbol();
let sym2 = Symbol();
let sym3 = Symbol('foo');
let sym4 = Symbol('foo');
console.log(sym1 == sym2); // false
console.log(sym3 == sym4); // false

不能new Symbol(),可以使用Object(mySymbol)将其包装为对象

3.4.7.2 使用全局符号注册表Symbol.for()

  • 当不同部分需要共享重用符号实例,可以用一个字符串作为键,在全局符号注册表中创建并重用符号

  • Symbol.for():当传入某个字符串调用时,会检查全局运行时注册表,如果发现不存在对应的符号,则新建并添加至注册表;如果发现与该字符串对应的符号,则重用

    let sym1 = Symbol.for('foo');
    let sym2 = Symbol.for('foo');
    console.log(sym1 == sym2); // true
    
  • 📢:在全局注册表中定义的符号与使用Symbol()定义的符号并不等同

    let sym1 = Symbol('foo');
    let sym2 = Symbol.for('foo');
    console.log(sym1 == sym2); // false
    
  • Symbol.for()的参数必须是字符串,不是字符串会转换为字符串

    let sym1 = Symbol.for();
    console.log(sym1); // undefined
    
  • 可以使用Symbol.keyFor()来查询全局注册表,该方法接收一个符号,返回全局符号中对应的字符串键;

    let sym1 = Symbol.for('foo');
    console.log(Symbol.keyFor(sym1)); // foo
    
    // 如果查询的不是全局符号而是普通符号,则返回undefined
    let sym2 = Symbol('bar');
    console.log(Symbol.keyFor(sym2)); // undefined
    
    // 如果传入Symbol.keyFor()的参数不是符号,则抛出TypeError错误
    Symbol.keyFor(123); // TypeError: 123 is not a symbol
    

3.4.7.3 使用符号作为属性

  • 凡是可以使用字符串或数值作为属性的地方,都可以使用符号

  • 包括了对象字面量属性、Object.defineProperty()Object.defineProperties()定义的属性

    // 对象字面量
    let s1 = Symbol('foo');
    let o = { [s1]: 'foo val' };
    console.log(o); // { Symbol(foo): foo val }
    
    // Object.defineProperty()
    let s2 = Symbol('bar');
    Object.defineProperty(o, s2, { value: 'bar val' });
    console.log(o); // { Symbol(foo): foo val, Symbol(bar): bar val }
    
    // Object.defineProperties()
    let s3 = Symbol('baz');
    let s4 = Symbol('qux');
    Object.defineProperties(o, {
      [s3]: { value: 'baz val' },
      [s4]: { value: 'qux val' }
    });
    console.log(o); // { Symbol(foo): foo val, Symbol(bar): bar val, Symbol(baz): baz val, Symbol(qux): qux val }
    
  • Object.getOwnPropertyNames()返回对象实例的常规属性数组

    let s1 = Symbol('foo');
    let s2 = Symbol('bar');
    
    let o = {
      [s1]: 'foo val',
      [s2]: 'bar val',
      baz: 'baz val',
      qux: 'qux val'
    };
    console.log(Object.getOwnPropertyNames(o)); // ['baz', 'qux']
    
  • Object.getOwnPropertySymbols()返回对象实例的符号属性数组

    console.log(Object.getOwnPropertySymbols(o));
    // [Symbol(foo), Symbol(bar)]
    
  • Object.getOwnPropertyDescriptors()同时返回包含常规和符合属性描述符的对象

    console.log(Object.getOwnPropertyDescriptors(o));
    // {baz: {…}, qux: {…}, Symbol(foo): {…}, Symbol(bar): {…}}
    
  • Reflect.ownKeys()会返回两种类型的键

    console.log(Reflect.ownKeys(o));
    // ['baz', 'qux', Symbol(foo), Symbol(bar)]
    

3.4.7.4 常用内置符号

TODO

3.4.8 Object类型

ECMAScript中的Object是派生其他对象的基类。Object类型的所有属性和方法在派生的对象上同样存在,每个Object实例都有如下属性和方法:

  • constructor: 用于创建当前对象的函数
  • hasOwnProperty(propertyName) : 用于判断当前对象实例(不是原型)上是否存在给定的属性,要检查的属性名必须是字符串或符号
  • isPrototypeOf(Object): 用于判断当前对象是否为另一个对象的原型
  • propertyIsEnumerable(propertyName): 用于判断给定的属性是否可以使用for-in语句枚举
  • toLocaleString(): 返回对象的字符串表示,该字符串反映对象所在的本地化执行环境
  • toString(): 返回对象的字符串表示
  • valueOf():返回对象对应的字符串、数值或布尔值表示。通常与toString()的返回值相同

3.5 操作符

3.5.1 一元操作符

3.5.1.1 递增/递减操作符

遵循如下规则

  • 对于字符串,如果是有效地数值形式,则转换为数值再应用改变。变量类型从字符串变成数值
  • 对于字符串,如果不是有效地数值形式,则将变量的值设置为NaN。变量类型从字符串变成数值
  • 对于布尔值,true转化为1,false转化为0,再进行操作。变量类型从布尔值变成数值
  • 对于浮点值,加1或减1
  • 如果是对象,则调用其valudOf()方法取得可以操作的值,再应用上述规则。如果是NaN,则调用toString()并再次应用其他规则。变量类型从对象变成数值

3.5.1.2 一元加和减

3.5.2 位操作符

ECMAScript中的所有数值都是以64位格式存储,但是位操作并不直接应用到64位表示,而是先把值转换为32位整数,再进行位操作,之后再把结果转换为64位。因此就只需要考虑32位整数即可

  • 有符号整数使用32位的前31位表示整数值,第32位表示数值的符号,0表示正,1表示负

  • 符号位决定了数值的其余部分的格式,正值以真正的二进制格式存储,负值以补码的二进制格式存储

    • 确定绝对值的二进制表示
    • 找到数值的反码,就是0变成1,1变成0
    • 给结果加1
  • 如果将位操作符应用到非数值,那么应该首先使用Number()将其转换为数值

3.5.2.1 按位非 ~

按位非的最终效果是对数值取反并减1,但是执行速度会比减1快的多

let num1 = 25;
let num2 = ~num1;
console.log(num2); // -26

3.5.2.2 按位与 &

let res = 25 & 3;
console.log(res); // 1

3.5.2.3 按位或 |

let res = 25 | 3;
console.log(res); // 27

3.5.2.4 按位异或 ^

let res = 25 ^ 3;
console.log(res); // 26

3.5.2.5 左移 <<

let value1 = 2;
let value2 = value1 << 5; // 64

左移会保留所操作数值的符号,比如-2左移5位,将得到-64

3.5.2.6 有符号右移 >>

let value1 = 64;
let value2 = 64 >> 5; // 2

右移之后空位会出现在左侧,且在符号位之后,会用符号位的值来填充这些空位

3.5.2.7 无符号右移 >>>

会将数值的所有32位都向右移

  • 对于正数,有符号右移和无符号右移的结果是一样的
  • 对于负数,无符号右移会给空位补0,差异会非常大

3.5.3 布尔操作符

3.5.3.1 逻辑非

  • 如果操作数是对象,则返回false
  • 如果操作数是空字符串,则返回true
  • 如果操作数是非空字符串,则返回false
  • 如果操作数是数值0,则返回true
  • 如果操作数是非0数值(包括Infinity),则返回false
  • 如果操作数是null、undefined或NaN,则返回true
  • 两个叹号(!!),相当于调用了转型函数Boolean(),无论操作数是什么类型,第一个叹号总会返回布尔值,第二个叹号对该布尔值取反,从而给出变量真正对应的布尔值

3.5.3.2 逻辑与

如果有操作数不是布尔值,则逻辑与并不一定返回布尔值,遵循如下规则

  • 如果第一个操作数是对象,则返回第二个操作数
  • 如果第二个操作数是对象,则只有第一个操作数求值为true才返回该对象
  • 如果两个操作数都是对象,则返回第二个操作数
  • 如果有一个操作数是null,NaN或者undefined,则返回null,NaN或undefined
  • 逻辑与操作具有短路操作

3.5.3.3 逻辑或

如果有一个操作数不是布尔值,那么逻辑或操作符也不一定返回布尔值,遵循如下规则

  • 如果第一个操作数是对象,则返回第一个操作数
  • 如果第一个操作数求值为false,则返回第二个操作数
  • 如果两个操作数都是对象,则返回第一个操作数
  • 如果两个操作数都是null或NaN或undefined,则返回null或NaN或undefined
  • 逻辑或也具有短路操作

3.5.4 乘性操作符

3.5.4.1 乘法操作符

  • 如果有任一操作数是NaN,则返回NaN

  • Infinity * 0 = NaN
    Infinity * Infinity = Infinity
    
  • 如果Infinity乘以非0的有限数值,则根据第二个操作符的符号返回Infinity-Infinity

  • 如果有不是数值的操作数,则先调用Number()将其转换为数值,再进行操作

3.5.4.2 除法操作符

  • 如果有任一操作数是NaN,则返回NaN

  • Infinity / Infinity = NaN
    0 / 0 = NaN
    
  • 如果是非0的有限值除以0,则根据第一个操作符的符号返回Infinity-Infinity

  • 如果是Infinity除以任何数值,则根据第二个操作数的符号返回Infinity-Infinity

  • 如果有不是数值的操作数,则先调用Number()函数将其转换为数值,再进行操作

3.5.4.3 取模操作符

  • 如果操作数是数值,则执行常规除法运算,返回余数
  • 如果被除数是无限值,除数是有限值,则返回NaN
  • 如果被除数是有限值,除数是0,则返回NaN
  • 如果是Infinity除以Infinity,则返回NaN
  • 如果被除数是有限值,除数是无限值,则返回被除数
  • 如果被除数是0,除数不是0,则返回0
  • 如果有不是数值的操作数,则先调用Number()函数将其转换为数值,再进行操作

3.5.5 指数操作符

console.log(Math.pow(3, 2)); // 9
console.log(3 ** 2); // 9

console.log(Math.pow(16, 0.5)); // 4
console.log(16 ** 0.5); // 4

3.5.6 加性操作符

3.5.6.1 加法操作符

  • 如果有任一操作符是NaN,则返回NaN

  • Infinity + Infinity = Infinity
    -Infinity + (-Infinity) = -Infinity
    Infinity + (-Infinity) = NaN
    
  • +0 + (+0) = +0;
    -0 + (+0) = +0;
    -0 + (-0) = -0;
    
  • 如果两个操作符都是字符串,则将第二个字符串拼接到第一个字符串后面

  • 如果只有一个操作数是字符串,则将第一个操作数转换为字符串,再将两个字符串拼接在一起

  • '5' + 5 // '55'

3.5.6.2 减法操作符

  • 如果有任一操作数是NaN,则返回NaN

  • Infinity - Infinity = NaN
    -Infinity - (-Infinity) = NaN
    Infinity - (-Infinity) = Infinity
    -Infinity - Infinity = -Infinity
    
  • +0 - (+0) = +0;
    +0 - (-0) = -0;
    -0 - (-0) = +0;
    
  • 如果任一操作数是字符串、布尔值、null、undefined,则先调用Number()将其转换为数值,再根据前面的规则执行运算;如果转换结果是NaN,则减法计算的结果是NaN

  • 如果任一操作数是对象,则调用其valueOf()方法取得表示它的数值。如果该值是NaN,则减法计算的结果是NaN;如果对象没有valueOf()方法,则调用其toString()方法,然后再将得到的字符串转换为数值

  • let res1 = 5 - '2'; // 3 先进行转换,所以结果是3 
    

3.5.7 关系操作符

比较规则:

  • 如果操作数是数值,则进行数值比较

  • 如果操作数都是字符串,则逐个比较字符串中对应字符的编码

    let res = 'Bab' < 'al'; // true
    let res = '23' < '3'; // true
    
  • 如果有任一操作数是数值,则将另一个操作数转换为数值,执行数值比较

    let res = '23' < 3; // false
    let res = 'a' < 3; // 'a'会转换为NaN,所以结果是false
    
  • 如果有任一操作数是对象,则调用其valueOf()方法,取得结果后再根据前面的规则执行比较。如果没有valueOf()操作符,则调用toString()方法,取得结果后再根据前面的规则进行比较

  • 如果有任一操作符是布尔值,则将其转换为数值再执行比较

  • 任何关系操作符在涉及比较NaN时都返回false

    let res = NaN < 3; // false
    let res = NaN >= 3; // false
    

3.5.8 相等操作符

3.5.8.1 等于和不等于

等于(==)或不等于(!==)在判断时会进行强制类型转换,且操作符遵循如下规则:

  • 如果任一操作数是布尔值,则将其转换为数值再比较是否相等,false转换为0,true转换为1
  • 如果一个操作数字符串,另一个操作数是数值,则尝试将字符串转换为数值,再比较是否相等
  • 如果一个操作数是对象,另一个操作数不是,则调用对象的valueOf()方法取得其原始值,再根据前面的规则进行比较
  • null和undefined相等
  • null和undefined不能转换为其他类型的值在进行比较
  • NaN和任何值都不相等,包括其自身
  • 如果两个操作符都是对象,则比较它们是不是同一个对象,是同一个对象返回true,否则False
表达式结果
null == undefinedtrue
false == 0true
true == 1true
true == 2false
undefined == 0false
null == 0false

3.5.8.2 全等和不全等

全等(===)和不全等(!==)操作符不会进行强制类型转换

  • null !== undefined
  • 推荐使用全等和不全等操作符

3.5.9 条件操作符

3.5.10 赋值操作符

3.5.11 逗号操作符

3.6 语句

3.6.1 if语句

3.6.2 do-while语句

循环体内在退出之前至少要执行一次

let i = 0;
do {
	i += 2;
} while (i < 10);

3.6.3 while语句

3.6.4 for语句

3.6.5 for-in语句

for-in语句用于枚举对象中的非符号键属性

// 推荐使用const
for (const propName in window) {
	document.write(propName);
}

ECMAScript中对象的属性是无序的,因此for-in语句不能保证返回对象属性的属性,也就是说,所有可枚举的属性都会返回一次,但返回的顺序可能会因浏览器而异

3.6.6 for-of语句

for-of语句y用于遍历可迭代对象的元素

// 推荐使用const
for (const el of [2, 4, 6, 8]) {
	console.log(el);
}

如果尝试迭代的变量不支持迭代,则for-of语法会抛出错误

3.6.7 标签语句

可以将标签与continuebreak结合起来使用

3.6.8 break和continue语句

3.6.9 with语句

不推荐使用with语句

3.6.10 switch语句

switch语句在比较每个条件的值时会使用全等操作符,因此不会强制转换数据类型

3.7 函数

如果没有返回值,函数会返回undefined

函数的具体内容会在后续内容解析

3.8 小结