zoukankan      html  css  js  c++  java
  • 【JavaScript高级程序设计4th】第3章 语言基础——总结(更新中)

    JavaScript高级程序设计4th第三章总结

    一、语法

    1. ECMAScript区分大小写

    2. 标识符

    变量、函数、属性或函数参数的名称:

    • 第一个字符必须是一个字母、下划线(_)或美元符号($);
    • 剩下的其他字符可以是字母、下划线(_)、美元符号或数字。

    最佳实践:ECMAScript标识符推荐使用驼峰大小写形式: 1 myCar maxOfNums

    注意:关键字、保留字、true、false 和 null 不能作为标识符。

    3. 注释

    1 // 单行注释
    2 
    3 /*
    4 *  多行注释
    5 */
    

    4. 严格模式

    ECMAScript增加了严格模式的概念。严格模式是一种不同的JavaScript解析和执行模型,ECMAScript3一些不规范写法在该模式下会被处理,对于不安全的的行为会抛出错误。

    1 // 启用严格模式
    2 "use strict"
    

    5. 语句

    ①ECMAScript语句以分号结尾。省略分号意味着又解析器确定语句在哪里结尾。为了避免输入内容不完整或者在某些情况下提高性能,推荐加上分号。

    ②对if语句而言,最佳实践是始终在控制语句中使用代码块,可以让内容更加清晰,修改代码时也可以避免出错:

    1 // 有效,容易导致错误,应该避免
    2 if (test)
    3     console.log(test);
    4 // 推荐
    5 if (test) { console.log(test);
    6 }
    

    二、关键字与保留字

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

    注意:关键字和保留字不能作为标识符

    三、变量

    ECMAScript变量是松散类型的,即变量可以用于保存任何类型的数据。每个变量只不过是一个用于保存任意值的命名占位符。

    声明变量的关键字: var:ECMAScript所有版本;let const:ECMAScript 6 及之后版本

    1. var关键字

    var message;
    // message变量可以保存任何类型的值;
    // 在不初始化的情况下,变量message保存undefined。
    var report = "hi";
    // report被定义为一个保存字符串值的变量,report并不会被标识为字符串类型;
    // report可以改变保存的值,或改变值的类型(有效,但不推荐)。
    

    ① var 声明作用域

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

     1 function test() {
     2     var message = "hi"; //局部变量
     3 }
     4 test();
     5 console.log(message); //error
    /*    
     *  在函数test()内定义的变量message,在执行完test()时(函数退出时)被销毁
    */
     9 
    10 function test() {
    11     message = "hi"; //全局变量
    12 }
    13 test();
    14 console.log(message); //error
    /*    
     *  省略var,则message被定义为全局变量,变量可以在函数外部被访问,不推荐
     *  在局部作用域中定义的全局变量很难维护,也容易造成局部/全局变量判断困惑。严格模式下,会抛出ReferenceError
    */
    

    ② var 声明提升

    提升(hoist),即把所有变量声明都拉到函数作用域的顶部。(反复多次使用var声明同一个变量也没有问题)

     1 function foo() {
     2     console.log(age);
     3     var age = 26;
     4 }
     5 foo(); // undefined
     6 // 等同于以下代码
     7 function foo() {
     8     var age;
     9     console.log(age);
    10     age = 26;
    11 }
    12 foo(); // undefined
    

    2. let 声明

    let与var作用差不多,但有着重要区别。

    区别之一是let声明的范围是块作用域,而var声明的范围是函数作用域

    if (true) {
        var name = "Matt";
        console.log(name); // Matt
    }
    console.log(name); //Matt
    
    if (true) {
        let age = 26;
        console.log(age); // 26
    }
    console.log(age); // ReferenceError: age 没有定义
    // 块作用域是函数作用域的子集
    

    区别之二是let不允许同一个块作用域中出现冗余声明。

    注意:对声明冗余报错不会因混用let和var而受影响,如下

    var name;
    let name; // SyntaxError
    
    let age;
    var age; // SyntaxError
    

    ①暂时性死区

    区别之三是let声明的变量不会在作用域中被提升。

    解析代码时,JavaScript引擎虽然会注意到块后的let的声明,但是此时不能以任何方式引用未声明的变量,否则将抛出ReferenceError。在let声明之前的执行瞬间称为“暂时性死区”。

    // name 会被提升
    console.log(name); // undefined
    var name = 'Matt';
    
    // age 不会被提升
    console.log(age); // ReferenceError: age 没有定义
    let age = 26;
    

    ②全局声明

    与var不同,使用let在全局作用域中声明的变量不会成为window对象的属性。但let声明仍然是在全局作用域中发生的,相应变量会在页面的生命周期内存续。重复声明会导致SyntaxError。

    var name = 'Matt';
    console.log(window.name); // Matt
    let age = 26;
    console.log(window.age); // undefined
    

    ③条件声明

    在使用var声明变量时,由于hoist,JavaScript引擎会自动将多余的声明在作用域顶部合并为一个声明。而let得作用域时块,故不能检查前面是否已经使用let声明过同名变量,即只能在没有声明过该变量的情况下声明它。
    这里的条件声明具体指的是:1.可以条件声明:使用var时,不必在意变量是否被声明过,直接假设为没有被声明过来处理(重新var声明)。2.不能条件声明:使用let时,不能假设没有被声明过因为此时let没有hoist。

    ④for循环中的let声明

    使用var在for循环中声明迭代变量,for循环定义的迭代变量会渗透到循环体外部;而let则不会,此时迭代变量的作用域仅限于for循环块内部。

    对迭代变量的奇特声明和修改(使用setTimeout超时查看):

    for(var i = 0; i < 5; ++i) {
      setTimeout(() => console.log(i), 0)
    }
    // 输出 5、5、5、5、5
    
    for(let i = 0; i < 5; ++i) {
      setTimeout(() => console.log(i), 0)
    }
    // 输出 0、1、2、3、4
    

    使用var,在退出循环时,迭代变量保存的是导致循环退出的值:5。在之后执行超时逻辑是,所有的i都是一个变量,故输出的都是同一个最终值。
    而使用let声明迭代变量时,JavaScript引擎在后台会为每个迭代循环声明一个新的迭代变量。每个setTimeout引用的都是不同的变量实例。

    3. const声明

    • const的行为与let基本相同,唯一一个重要区别是「用const声明变量是必须同时初始化变量,且尝试修改const声明的变量会导致运行时错误」
    • const声明的限制只适用于它指向的变量的引用
    • 与let不同,即使JavaScript引擎会为for循环中的let声明分别创建独立的变量实例,而且const和let很相似,但也不能用const来声明迭代变量(迭代变量会自增)。
      • 用const声明一个不会被修改的for循环变量是可以的。即每次迭代只是创建一个新变量。这对for-of和for-in循环特别有意义,参考下图。
    // 1.声明的变量不能被改变
    for (const i = 0; i < 10; ++i) {} //TypeError
    
    // 2. 可以声明不被修改的for循环变量
    let i = 0;
    for (const j =7; i < 5; ++i) {
      console.log(j);
    }
    // 7,7,7,7,7
    
    // 3. const在for-in中的应用
    for (const key in {a: 1, b: 2}) {
      console.log(key);
    }
    // a, b
    
    // 4. const在for-in中的应用
    for (const key of [1,2,3,4,5]) {
      console.log(key);
    }
    // 1,2,3,4,5
    
    • 对为什么const可以在for-in和for-of中使用,而不能在for循环使用的理解:
    1. let
    for (let i = 0; i < 5; i++) {
      console.log(i);
    }
    // 0,1,2,3,4
    // 相当于
    let i = 0;
    while(i < 5) {
      console.log(i);
      i++;
    }
    // 0,1,2,3,4
    // for循环只初始化一次变量,每一次循环都是在同个块级作用域中进行
    
    1. const for-in
    for (const key in {a: 1, b: 2}) {
      console.log(key);
    }
    // a,b
    // 遍历的是对象的属性值,相当于
    var a = {a: 1, b: 2};
    var b = Object.keys(a).entries();
    while(true)
    {
         const c = b.next();
         if(c.done) break;
         const key =  c.value[1];
         console.log(key);
     }
    // a,b
    // 即,for-in循环会为每一次循环都会产生一个块级作用域去完成该变量的行为
    
    1. const for-of
    for (const key of [1,2,3,4,5]) {
      console.log(key);
    }
    // 1,2,3,4,5
    // 相当于
    var a = [1,2,3,4,5];
    var b = a.entries();
    while(true) {
      const c = b.next();
      if (c.done) break;
      const key = c.value[1];
      console.log(key);
    }
    // 与for-in一样,for-of是严格的迭代语句,每次循环都会产生一个块级作用域,故const不会重复赋值
    

    4. 声明风格及最佳实践

    ①不使用var

    ②const优先,let次之

    四、数据类型

    ECMAScript的类型系统是松散的,它有6种数据类型(原始类型):Undefined、Null、Boolean、Number、String和Symbol(符号,是ES6新增的),1种复杂数据类型:Object(无序名值对的集合)。和其他高级语言如C++不一样,ECMAScript中不能定义自己的数据类型,即没有XX类型的变量之分。

    1.typeof操作符

    • 为什么要有typeof?

    ECMAScript松散的类型系统

    • typeof操作符可能返回的字符串值有:“undefined”(表示值未定义)、“boolean”(值为布尔值)、“string”(值为字符串)、“number”(值为数值)、“object”(表示值为对象(非函数)或null)、“function”(值为函数)、symbol(值为符号)。
    • 【注意】
      1. typeof ("hello")正确吗?

      typeof是操作符,而非函数,故不需要参数,但可以使用参数。

      1. 为什么typeof null返回的是“object”?

      特殊值null被认为是一个空对象的引用。

      1. 为什么typeof操作符的返回值会有“function”?

      函数在ECMAScript中被认为是对象,并不是一种数据类型。但是由于函数有自己特殊的属性,因此有必要通过typeof来区分函数和其他对象。

    2. Undefined 类型

    • 什么情况下,变量的是Undefined类型的?Undefined类型有哪些值?

    当使用var或者let声明了变量却没有初始化时,该变量的值是undefined类型的;Undefined类型只有一个值:undefined。

    • 包含undefined值的变量和未定义变量是有区别的:
    let message;
    // let age; 没有被声明过
    console.log(message); // "undefined"
    console.log(age); // 报错,Uncaught ReferenceError: age is not defined
    
    • typeof与undefined的奇怪之处:对未声明的变量使用typeof操作符和调用delete是不会报错的(其中,在严格模式下这样使用delete会报错)。
    typeof age
    // "undefined"
    
    let message; typeof message;
    // "undefined"
    

    3. Null 类型

  • 相关阅读:
    vue 子页面,向父页面 传值...
    pre 标签 防止 其撑开 div...
    Vue 父页面 值传递 不到 子组件....
    Mysql tips 功能...
    mysql 配置utf8 编码,支持 emoji 方法!!!
    DataGrip 使用--方法-..../
    百度地图 api bug 解决.......
    民生银行信用卡销卡指南
    古董留念
    Microsoft Office 2010 Service Pack 2 发布更新
  • 原文地址:https://www.cnblogs.com/pmcee/p/14479657.html
Copyright © 2011-2022 走看看