let

let 类似于 var 但是let 声明的变量只在let 命令所在的代码块内有效

    {
      let a = 10;
      var b = 1;
    }
    a//ReferenceError: a is not defined.
    b//1

var 有变量提升,let 命令改变了语法行为,不存在变量提升。

暂时性死区(TDZ)-在代码块内,使用 let 命令声明变量之前,该变量都是不可用的。

     var temp = 123;
     if(true){
       temp = "123"; //ReferenceError
       let temp;//let 声明的 temp 绑定了 if 这个块级作用域
     }

     if(true){
       //TDZ开始
       temp = "123"; //ReferenceError
       console.log(temp)//ReferenceError
       
       let temp;//TDZ结束
       console.log(temp)//undifined
       
       temp = 123;
       console.log(temp)//123
     }

let 不允许在相同作用域内,重复声明同一个变量

块级作用域

     function f1(){
       let n = 5;
       if(true){
         let n = 10;
         console.log('1',n); //10
       }
       console.log('2',n); // 5 外层代码块不受内层代码块的影响。
     }
     
     
     {{{{
       {let isane = 'Hello World'}
       console.log(insane);// 报错 每一层都是单独的作用域
     }}}}

块级作用域的出现,使得匿名立即执行函数表达式(匿名 IIFE )不再必要。

const

const 声明一个只读的常量。一旦声明,常量的值就不能改变。const 的作用域与 let 命令相同:只在声明所在的块级作用域内有效。

本质上const 保证的是变量指向的那个内存地址所保存的数据不得改动,而不是变量的值不得改动。对于简单类型的数据(数值、字符串、布尔值),值就保存再变量指向的那个内存地址。对于复合类型的数据(主要是对象和数组),变量指向的内存地址,保存的只是一个指向实际数据的指针,const只能保证这个指针是固定的,至于它指向的数据结构是不是可变的,就完全不能控制了。

      const foo = {};
      
      foo.prop = 123;
      foo.prop //123
      
      //指向另一个对象时报错
      foo = {}//TypeError: "foo" is read-only
      

ES5 只有两种声明变量的方法

  • var
  • function

这两个命令声明的全局变量,依旧是顶层对象的属性

ES6中添加了四种声明变量的方法

  • let
  • const
  • import
  • class

let、 const、class命令声明的全局变量,不属于顶层对象的属性

     var a = 1;
     window.a //1
     
     let b = 1;
     window.b //undifined

字符串的扩展

  • Unicode表示法。ES6 加强了对Unicode 的支持,允许采用 \uxxxx 形式表示一个字符,xxxx 表示字符的Unicode码点。仅限于\u0000~\uFFFF的字符 超过的需要用两个双字节的形式表示。"\uD842\uDFB7" 如果在\u 后面跟上超过0xFFFF的数值需要将码点放入大括号。'\u{1F680}' === '\uD83D\uDE80'
  • 字符串的遍历器接口 字符串可以被 for...of 循环遍历 for(let codePoint of 'foo'){ console.log(codePoint) } //'f' //'o' //'o'
  • 模板字符串 ${}

字符串的新增方法

  • String.fromCodePoint() - 用于从Unicode 码点返回对应字符(可以识别码点大于0xFFFF的字符,对比ES5中的 String.fromCharCode())

  • String.raw() - 返回一个斜杠都被专业(即斜杠前面再加一个斜杠)的字符串。(用于模板字符串的处理方法)

  • 实例方法:codePointAt() - 能够正确处理4个字节储存的字符,返回一个字符的码点。

  • 实例方法:normalize() - 用来将字符的不同表示方法统一为同样的形式,这称为Unicode正规化

  • 实例方法:includes() - 返回布尔值,表示是否找到了参数字符串

  • 实例方法:startsWith() - 返回布尔值,表示参数字符串是否再原字符串的头部

  • 实例方法:endsWith() - 返回布尔值,表示参数字符串是否在原字符串的尾部

  • 实例方法:repeat() - 返回一个新字符串,表示将原字符串重复n次

  • 实例方法:padStart() padEnd() - 某个字符串不够指定长度,会在头部(padStart())或者尾部(padEnd())补全。它们一共接受两个参数,第一个参数是字符串补全生效的最大长度,第二个参数是用来补全的字符串

  • 实例方法:trimStart() trimEnd() - trimStart()消除字符串头部的空格,trimEnd() 消除尾部的空格。(返回新的字符串,不会修改原始字符串。)

  • 实例方法:matchAll() - 返回正则表达式在当前字符串的所有匹配

  • 实例方法:repalaceAll() - 可以一次性替换所有匹配(返回新的字符串,不会修改原始字符串。)

  • 实例方法:at() - 接受一个整数作为参数,返回参数指定位置的字符,支持负索引(即倒数的位置)

       let s = "hello";
       console.log(s.startsWith('he',1)); //false
       console.log(s.endsWith('h',1));//true
       console.log(s.includes('he',5));//false
    
       console.log(s.repeat(2));//hellohello
    
       console.log(s.padStart(10,"22"));//22222hello
       console.log(s.padEnd(10,"22"));//hello22222
    
       let str = '   123   '
       console.log(str.trim());//123
       console.log(str.trimStart());//'123   '
       console.log(str.trimEnd());//'   123'
       console.log(str);//'   123   '
    
       console.log(s.replace('l','0'));//he0lo
       console.log(s.replaceAll('l','0'));//he00o
       console.log(s);//hello
    
       console.log(s.at(1));//e
       console.log(s.at(-1));//o
       
    

数值的扩展

  • 提供了二进制和八进制数值的新的写法,分别用前缀“0b(0B)”和“0o(0O)”

  • 数值分隔符(增加数值的可读性,只是一种书写遍历,对于JavaScript内部数值的存储和输出没有影响)

  • Number.isFinite() - 检查一个数值是否为有限的(非数值类型都返回false)

  • Number.isNaN() - 检查一个值是否为NaN(非NaN都返回false)

  • 将全局方法parseInt() parseFloat()移植到Number对象上,行为保持不变

  • Number.isInteger() - 用来判断一个数值是否为整数(如果对数据精度要求较高,不建议使用Number.isInteger())

  • Number.EPSILON - 一个极小的常量,表示1与大于1的最小浮点数之间的差。

  • 安全整数 JavaScript能够准确表示的整数范围在-2^53到2^53之间。Number.MAX_SAFE_INTEGER表示 2^53;Number.MIN_SAFE_INTEGER表示-2^53。Number.isSafeInteger() - 判断一个整数是否落在这个范围之内。

       (function(){
         'use strict'
         console.log(0O11===011)
       })()//Octal literals are not allowed in strict mode
       console.log(Number('0b111'));//7 转十进制用Number方法
    
       console.log(Number.isFinite(222));//true
       console.log(Number.isFinite(Infinity));//false
       console.log(Number.isFinite(true));//false
    
       console.log(Number.isNaN(2333));//false
       console.log(Number.isNaN(NaN));//true
       console.log(Number.isNaN(true));//false
       console.log(Number.isNaN('true'/'true'));//true
    
    
       console.log(Number.parseFloat === parseFloat);//true
       console.log(Number.parseInt === parseInt);//true
    
       console.log(Number.isInteger(25));//true
       console.log(Number.isInteger(25.1));//false
    
       console.log(Number.isInteger(25.0));//true
    
       console.log(Number.isInteger(3.0000000000000000002));//true
    
  • Math 对象的扩展

  1. Math.trunc() - 去除一个数的小数部分,返回整数部分。

  2. Math.sign() - 判断一个数到底是正数、负数、还是零。

  3. Math.cbrt() - 计算一个数的立方根

  4. Math.clz32() - 将参数转为 32 位无符号整数的形式,然后返回这个32位值里面有多少隔前导0

  5. Math.imul() - 返回两个数以32位带符号整数形式相乘的结果,返回的也是一个32位的带符号整数。

  6. Math.fround() - 返回一个数的32位单精度浮点数形式(将64位双精度浮点数转为32位单精度浮点数)

  7. Math.hypot() - 返回所有参数的平方和的平方根

  8. Math.expm1(x) - 返回Math.exp(x)-1

  9. Math.log1p(x) - 返回 1+x 的自然对数,即Math.log(1+x)

  10. Math.log10(x) - 返回以10为底的x的对数

  11. Math.log2(x) - 返回以2为底的x的对数

  12. Math.sinh(x) 返回x的双曲正弦(hyperbolic sine)

  13. Math.cosh(x) 返回x的双曲余弦(hyperbolic cosine)

  14. Math.tanh(x) 返回x的双曲正切(hyperbolic tangent)

  15. Math.asinh(x) 返回x的反双曲正弦(inverse hyperbolic sine)

  16. Math.acosh(x) 返回x的反双曲余弦(inverse hyperbolic cosine) 17.Math.atanh(x) 返回x的反双曲正切(inverse hyperbolic tangent)

      console.log(Math.trunc(22)); //22
      console.log(Math.trunc(22.22));//22
      console.log(Math.trunc(-22.22));//-22
      console.log(Math.trunc(0));//0
      console.log(Math.trunc(-0.005));//-0
    
      console.log(Math.sign(2)); //+1
      console.log(Math.sign(-2));//-1
      console.log(Math.sign(0));//+0
      console.log(Math.sign(-0));//-0
      console.log(Math.sign('true'));//NaN
    
      console.log(Math.cbrt(27));//3
      console.log(Math.cbrt(1));//1
    
      console.log(Math.clz32(0));//32
      console.log(Math.clz32(1000));//22
    
      console.log(Math.imul(2,2)); // 4
      console.log(Math.imul(-2,2)); // -4
    
    
      console.log(Math.fround(1.25));//1.25
      console.log(Math.fround(0.3));//0.30000001192092896
    
      console.log(Math.hypot(3,4));//5
    
  • BigInt 数据类型 BigInt 只用来表示整数,没有位数的限制。BigInt类型的数据必须添加后缀 n

       const a = 21712312748n;
       const b = 123124454555n;
       console.log(a*b);//2673316664225073167140n
       console.log(Number(a)*Number(b));//2.673316664225073e+21
       42n!==42//true
       
    

函数的扩展

  • 允许为函数的参数设置默认值,即直接写在参数定义的后面

       function point(x = 0,y = 0){
         this.x = x;
         this.y = y;
       }
    
  • 参数默认值可以与解构赋值的默认值结合起来使用。

       function foo({x,y=5}){
         console.log(x,y)
       }
       foo({})// undifined 5
       foo(1,2)// undifined 5
       foo({x:1}) //1 5
    
  • rest参数 (形式为 ...变量名 )用于获取函数的多余参数。 rest 参数只能是最后一个参数

       //arguments 变量的写法
       function sortNumbers(){
         retrun Array.from(arguments).sort();
       }
       //rest 参数的写法
       const sortNumbers = (...numbers) =>numbers.sort();
    
  • 箭头函数 (=>)

  1. 箭头函数没有自己的 this 对象
  2. 不可以当作构造函数,不可以对箭头函数使用new命令
  3. 不可以使用arguments对象,该对象在函数体中不存在。可以使用rest参数代替
  4. 不可以使用yield命令,不能用作Generator函数
  • 尾调用优化
  • 尾递归

数组的扩展

  • 扩展运算符 (...

       console.log(...[1,2,3])//1 2 3 
       let arr1 = [1,2,3]
       let arr2 = [4,5,6]
       arr1.push(...arr2)
    
  • Array.from() - 用于将两类对象转为真正的数组:类似数组的对象(array-like object)和可遍历(iterable)的对象

       let arrayLike = {
         '0':'a',
         '1':'b',
         '2':'c',
         length:3
       }
       
       let arr2 = Array.from(arrayLike)// ['a','b','c']
       
    
  • Array.of() - 用于将一组值转换为数组

       Array.of(3,11,8)//[3,11,8]
       
    
  • 实例方法:copyWithin() - 在当前数组内部,将指定位置的成员复制到其他位置(会覆盖原有成员),然后返回当前数组。

  • find() - 用于找出第一个符合条件的数组成员,如果没有符合条件的成员,则返回undefined

  • findIndex() - 用于找出第一个符合条件的数组成员的位置,如果没有符合条件的成员,则返回-1

  • fill() - 使用给定值,填充一个数组

  • entries() - 对键值对的遍历

  • keys() - 对键名的遍历

  • values() - 对键值的遍历

  • includes() - 返回一个布尔值,表示某个数组是否包含给定的值。

  • flat() - 将嵌套的数组“拉平”

       [1, 2, [3, 4]].flat()
       // [1, 2, 3, 4]
       [1, [2, [3]]].flat(Infinity)
       // [1, 2, 3]如果不管有多少层嵌套,都要转成一维数组,可以用Infinity关键字作为参数。
    
  • flatMap() - 原数组的每个成员执行一个函数(相当于执行Array.prototype.map()),然后对返回值组成的数组执行flat()方法。

       // 相当于 [[2, 4], [3, 6], [4, 8]].flat()
       [2, 3, 4].flatMap((x) => [x, x * 2])
       // [2, 4, 3, 6, 4, 8]flatMap()只能展开一层数组。
    
  • at() - 接受一个整数作为参数,返回对应位置的成员,支持负索引。

对象的扩展

  • 属性的简洁表示法 允许在大括号里面直接写入变量和函数,作为对象的属性和方法。

  • 属性名表达式 一是直接用标识符作为属性名 二是用表达式作为属性名。(属性名表达式不能与简洁表示法同时使用)

  • 方法的name属性 函数的name属性,返回函数名。使用了取值函数(getter)和存值函数(setter)则name属性不是在该方法上 而是在该方法的属性的描述对象的get和set属性上。

       const person ={
       sayName(){
         console.log("hello!");
       }
     }
     console.log(person.sayName.name);//sayName
    
     const obj={
       get foo(){},
       set foo(x){}
     };
     // console.log(obj.foo.name);//Uncaught TypeError: Cannot read properties of undefined (reading 'name')
    
     const descriptor = Object.getOwnPropertyDescriptor(obj,'foo')
     console.log(descriptor.get.name); //get foo
     console.log(descriptor.set.name);// set foo
    
  • 属性的可枚举性和遍历

遍历的方法:

  1. for...in - 遍历对象自身的和继承的可枚举属性(不含Symbol属性)
  2. Object.keys(obj) - 返回一个数组,包括对象自身的(不含继承的)所有可枚举属性(不含Symbol属性)的键名
  3. Object.getOwnPropertyNames(obj) - 返回数组,包含对象自身的所有属性(不含Symbol属性,但是包括不可枚举属性)的键名
  4. Object.getOwnPropertySymbols(obj) - 返回一个数组,包含对象自身的所有Symbol 属性的键名
  5. Reflect.ownKeys(obj) - 返回一个数组,包含对象自身的(不含继承的)所有键名,不管键名是Symbol或字符串,也不管是否可枚举。

它们都遵循

  1. 首先遍历所有数值键,按照数值升序排序

  2. 其次遍历所有字符串键,按照加入事件升序排序

  3. 最后遍历所有Symbol 键,按照加入事件升序排列

    function Doo(a){
      this.a = a 
    }
    let obj1 = new Doo(1)
    obj1.foo = 123
    obj1.fee = 234
    
    for (key in obj1){
      console.log(key); // a  foo  fee
    }
    
    console.log(Object.keys(obj1));//['a', 'foo', 'fee']
    console.log(Object.getOwnPropertyNames(obj1));//['a', 'foo', 'fee']
    console.log(Object.getOwnPropertySymbols(obj1));//['a', 'foo', 'fee']
    console.log(Reflect.ownKeys({ [Symbol()]:0, b:0, 10:0, 2:0, a:0 }));//['2', '10', 'b', 'a', Symbol()]
    
    let obj = {foo:123,fee:234}
    const descriptor = Object.getOwnPropertyDescriptor(obj,'foo')
    console.log(descriptor);
    /*{
        configurable: true
        enumerable: true
        value: 123
        writable: true
      }
    */
    
  • super 关键字 - 指向当前对象的原型对象(只能用在对象的方法之中,用在其他地方都会报错)

对象的新增方法

  • Object.is() - 用来比较两个值是否严格相等
  • Object.assign() - 用于对象的合并
  1. 实行的浅拷贝
  2. 同名属性直接替换
  3. 可以处理数组,但是会把数组视为对象
  4. 如果复制取值函数,那么将求值后再复制
  • Object.getOwnPropertyDescriptors() - 返回某个对象属性的描述对象(descriptor)
  • __proto__属性,Object.setPrototyprOf() ,Object.getPrototyprOf()
  • Object.keys(),Object.values(),Object.entries()
  • Object.fromEntries() - 是Object.entries()的逆操作,用于将一个键值对数组转为对象

运算符的扩展

  • ** - 指数运算符(当有多个指数运算符时,先计算最右边的再往左计算)
  • ?. - 链判断运算符 判断左侧的对象是否为null或者undefined。如果是,就不再往下计算,而是返回undefined
  1. obj?.prop //对象属性是否存在

  2. obj?.[expr]//同上

  3. func?.(...args)//函数或对象方法是否存在

    a?.b
    //等同于
    a == null ? undefined : a.b
    a?.[x]
    //等同于
    a == null ? undefined : a[x]
    a?.b()
    //等同于
    a == null ? undefined : a.b()
    a?.()
    //等同于
    a == null ? undefined : a()
    
    console.log(Object.is('foo','foo')); //true
    console.log(Object.is(+0,-0));  // false
    console.log(Object.is(NaN,NaN)); // true
    
    const obj1 = {a:1}
    const source1 = {b:2}
    const source2 = {c:3}
    
    console.log(Object.assign(obj1,source1,source2));// {a:1,b:2,c:3}
    
    let {keys,values,entries} = Object;
    let obj = {a:1,b:2,c:3}
    
    for(let key of keys(obj)){
      console.log(key); // 'a','b','c'
    }
    
    for(let value of values(obj)){
      console.log(value); // 1,2,3
    }
    
    for(let [key,value] of entries(obj)){
      console.log([key,value]); //['a',1],['b',2],['c',3]
    }
    
    let a = Object.fromEntries([
      ['a',1],
      ['b',3]
    ])
    console.log(a);//{a:1,b:3}
    
    console.log(2**3);//8
    console.log(2**3**2);//2**(3**2) 2**9  512
    

Symbol

Symbol 表示独一无二的值,主要是解决对象属性名可能会相同导致冲突的情况。