ES6标准入门 第3版 读书笔记1

目录2:let 和 const 命令

  1. var 存在变量提升。为了纠正这个现象,let,const 声明的变量会产生“暂时性死区”
    暂时性死区的本质:只要进入当前作用域,所使用的变量就已经存在,但是不可获取。只有等到声明变量的那一行代码出现,才可以获取和使用该变量。
  2. let const 不允许在相同作用域内重复声明一个变量。var 可以!
  3. ES5规定,函数只能在顶层作用域和函数作用域内声明,不能在块级作用域声明。 但为了兼容以前的旧代码,浏览器并没有遵循这个规定,还是支持在块级作用域内声明函数,函数会被提升到顶部;
  4. ES6引入了块级作用域,明确可以在块级作用域中声明函数。ES6规定,块级作用域之中,函数声明语句的行为类似于let,在块级作用域之外不可引用。但是,实际上,为了减轻因此产生的不兼容问题,浏览器可以不遵守上面的规定,有自己的行为方式(只对ES6浏览器有效):
    • 允许在块级作用域内声明函数。
    • 函数声明类似于var,即会提升到全局作用域或函数作用域的头部。
    • 同时,函数声明还会提升到所在的块级作用域的头部。
    // 浏览器的 ES6 环境
    function f() { console.log('I am outside!'); }
    
    (function () {
      if (false) {
        // 重复声明一次函数f
        function f() { console.log('I am inside!'); }
      }
    
      f();
    }());
    // Uncaught TypeError: f is not a function
    
    实际运行如下:
    // 浏览器的 ES6 环境
    function f() { console.log('I am outside!'); }
    (function () {
      var f = undefined;
      if (false) {
        function f() { console.log('I am inside!'); }
      }
    
      f();
    }());
    // Uncaught TypeError: f is not a function
    
    注意:
    • 考虑到环境导致的行为差异太大,应该避免在块级作用域内声明函数。如果确实需要,应写成函数表达式。

    • ES6的块级作用域必须有大括号

      // 第一种写法,报错 没有大括号,所以不存在块级作用域,而let只能出现在当前作用域的顶层
      if (true) let x = 1;
      
      // 第二种写法,不报错
      if (true) {
        let x = 1;
      }
      
    • 函数声明也是如此,严格模式下,函数只能声明在当前作用域的顶层。

  5. const 实际上保证的,并不是变量的值不得改动,而是变量指向的那个内存地址所保存的数据不得改动。如果想将对象冻结,应该使用Object.freeze()方法。
    const foo = Object.freeze({});
    
    // 常规模式时,下面一行不起作用;
    // 严格模式时,该行会报错
    foo.prop = 123;
    
    除了将对象本身冻结,对象的属性也应该冻结:
    var constantize = (obj) => {
      Object.freeze(obj);
      Object.keys(obj).forEach( (key, i) => {
        if ( typeof obj[key] === 'object' ) {
          constantize( obj[key] );
        }
      });
    };
    
  6. ES5有两种声明变量的方法:varfunction。ES6除了letconst,还有importclass
  7. 顶层对象:在浏览器中指window对象,在Node中指global对象。ES5中,顶层对象的属性和全局变量是等价的。但是在ES6中,var function声明的全局变量依旧是顶层对象的属性,而 let const class声明的全局变量不属于顶层对象的属性。
var a = 1;
// 如果在 Node 的 REPL 环境,可以写成 global.a
// 或者采用通用方法,写成 this.a
window.a // 1

let b = 1;
window.b // undefined
  1. 顶层对象在各种实现里面是不统一的:
    • 浏览器,顶层对象获取:windowselfframes, 全局环境中的this , 函数不作为对象的方法运行,而是单纯作为函数运行,this会指向顶层对象,但是严格模式下,返回undefined
    • Web Worker,顶层对象获取:self
    • Node,顶层对象获取:global
    • ES2020引入了globalThis作为顶层对象,任何环境下都可以通过它拿到顶层对象;

目录3:变量的解构赋值

  1. ES6内部使用严格相等运算符===,来判断一个位置是否有值。只有严格等于undefined,默认值才会生效。
  2. 对象的解构与数组的解构有一个重要的不同。数组的元素是按次序排列的,变量的取值由它的位置决定;而对象的属性没有次序,变量必须与属性名同名,才能取到正确的值;
  3. 解构失败等于undefined
  4. 对象解构,如果变量名与属性名不一致,必须写成下面这样:
let { foo: baz } = { foo: 'aaa', bar: 'bbb' };
baz // "aaa"

let obj = { first: 'hello', last: 'world' };
let { first: f, last: l } = obj;
f // 'hello'
l // 'world'
  1. 对象的解构赋值可以取到继承的属性
  2. 注意点:
    • 将一个已经声明的变量用于解构赋值,需要非常小心:
    // 错误的写法
    let x;
    {x} = {x: 1};
    // SyntaxError: syntax error
    
    // 正确的写法
    let x;
    ({x} = {x: 1});
    
    • 解构赋值允许等号左边的模式之中,不放置任何变量名:
    ({} = [true, false]);
    ({} = 'abc');
    ({} = []);
    
    • 数组本质是特殊的对象,因此可以对数组进行对象属性的解构:
    let arr = [1, 2, 3];
    let {0 : first, [arr.length - 1] : last} = arr;
    first // 1
    last // 3
    
  3. 字符串也可以解构赋值,如下:字符串会被转换为一个类似数组的对象:
    类似数组的对象都有一个length属性,因此还可以对这个属性解构赋值
    const [a, b, c, d, e] = 'hello';
    a // "h"
    b // "e"
    c // "l"
    d // "l"
    e // "o"
    
    let {length : len} = 'hello';
    len // 5
    
  4. 解构赋值的规则是:只要等号右边的值不是对象或数组,就先将其转为对象。由于,undefinednull无法转为对象,所以对它们进行解构赋值,都会报错。
  5. 解构赋值中,不能使用圆括号:变量声明语句,函数参数,赋值语句的模式; 可以使用圆括号:赋值语句的非模式部分;
    10.变量解构赋值的用途:
    • 交换变量的值
    • 从函数返回多个值
    • 函数参数的定义
    • 提取JSON数据
    • 函数参数的默认值
    • 遍历Map结构
    • 输入模块的指定方法

目录四:字符串的扩展

  1. 字符的Unicode表示法;ES6加强了对Unicode的支持,允许采用\uxxxx形式表示一个字符,其中xxxx表示字符的Unicode码点;
    '\z' === 'z'  // true
    '\172' === 'z' // true
    '\x7A' === 'z' // true
    '\u007A' === 'z' // true
    '\u{7A}' === 'z' // true
    
  2. ES6为字符串添加了遍历器接口iterator,使得字符串可以被for ... of循环遍历
    传统的for循环无法识别这样的码点
    let text = String.fromCodePoint(0x20BB7);
    //for循环会认为它包含两个字符(都不可打印)
    for (let i = 0; i < text.length; i++) {
      console.log(text[i]);
    }
    // " "
    // " "
    
    for (let i of text) {
      console.log(i);
    }
    // "𠮷"
    
  3. 根据标准,JSON数据必须是UTF-8编码。但是JSON.stringify()方法有可能返回不符合UTF-8标准的字符串。UTF-8标准规定,0xD8000xDFFF之间的码点,不能单独使用,必须配对使用;比如,\uD834\uDF06是两个码点,但是必须放在一起配对使用,代表字符𝌆。这是为了表示码点大于0xFFFF的字符的一种变通方法。
    JSON.stringify()的问题在于,它可能返回0xD8000xDFFF之间的单个码点。为了确保返回的是合法的UTF-8字符,ES2019改变了JSON.stringify()的行为。如果遇到0xD8000xDFFF之间的单个码点,或者不存在的配对形式,它会返回转义字符串,留给应用自己决定下一步的处理。·
JSON.stringify('\u{D834}') // ""\\uD834""
JSON.stringify('\uDF06\uD834') // ""\\udf06\\ud834""

目录5:字符串的新增方法

  1. ES5提供String.fromCharCode()方法,用于从Unicode码点返回对应字符,但是这个方法不能识别码点大于0xFFFF的字符;
  2. ES6提供了String.fromCodePoint()方法,可识别大于0xFFFF的字符;
  3. 传统上,JS只有indexOf方法,用来确定一个字符串是否包含在另一个字符串中。ES6又提供了三种新的方法:
    • includes():返回布尔值,表示是否找到了参数字符串。
    • startsWith():返回布尔值,表示参数字符串是否在原字符串的头部。
    • endsWith():返回布尔值,表示参数字符串是否在原字符串的尾部。
  4. 实例方法:normalize() includes() startsWith() endsWith()
  • repeat() :返回一个新的字符串,将原字符串重复n次
  • ES2017引入了字符串补全长度的功能;如果某个字符串不够指定长度,会在头部或尾部补全;padStart()用于头部补全,padEnd()用于尾部补全;
    第一个参数是字符串补全生效的最大长度,第二个参数是用来补全的字符串。
    'x'.padStart(5, 'ab') // 'ababx'
    'x'.padStart(4, 'ab') // 'abax'
    
    'x'.padEnd(5, 'ab') // 'xabab'
    'x'.padEnd(4, 'ab') // 'xaba'
    
  • ES2019对字符串实例新增了trimStart()trimEnd()方法;它们的行为与trim()一致,trimStart()消除字符串头部的空格,trimEnd()消除尾部的空格。它们返回的都是新字符串,不会修改原始字符串。
    浏览器还部署了额外的两个方法,trimLeft()trimStart()的别名,trimRight()trimEnd()的别名。
  • matchAll()方法返回一个正则表达式在当前字符串的所有匹配;
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章