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 对象的扩展
-
Math.trunc() - 去除一个数的小数部分,返回整数部分。
-
Math.sign() - 判断一个数到底是正数、负数、还是零。
-
Math.cbrt() - 计算一个数的立方根
-
Math.clz32() - 将参数转为 32 位无符号整数的形式,然后返回这个32位值里面有多少隔前导0
-
Math.imul() - 返回两个数以32位带符号整数形式相乘的结果,返回的也是一个32位的带符号整数。
-
Math.fround() - 返回一个数的32位单精度浮点数形式(将64位双精度浮点数转为32位单精度浮点数)
-
Math.hypot() - 返回所有参数的平方和的平方根
-
Math.expm1(x) - 返回Math.exp(x)-1
-
Math.log1p(x) - 返回 1+x 的自然对数,即Math.log(1+x)
-
Math.log10(x) - 返回以10为底的x的对数
-
Math.log2(x) - 返回以2为底的x的对数
-
Math.sinh(x) 返回x的双曲正弦(hyperbolic sine)
-
Math.cosh(x) 返回x的双曲余弦(hyperbolic cosine)
-
Math.tanh(x) 返回x的双曲正切(hyperbolic tangent)
-
Math.asinh(x) 返回x的反双曲正弦(inverse hyperbolic sine)
-
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();
-
箭头函数 (=>)
- 箭头函数没有自己的 this 对象
- 不可以当作构造函数,不可以对箭头函数使用new命令
- 不可以使用arguments对象,该对象在函数体中不存在。可以使用rest参数代替
- 不可以使用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
-
属性的可枚举性和遍历
遍历的方法:
- for...in - 遍历对象自身的和继承的可枚举属性(不含Symbol属性)
- Object.keys(obj) - 返回一个数组,包括对象自身的(不含继承的)所有可枚举属性(不含Symbol属性)的键名
- Object.getOwnPropertyNames(obj) - 返回数组,包含对象自身的所有属性(不含Symbol属性,但是包括不可枚举属性)的键名
- Object.getOwnPropertySymbols(obj) - 返回一个数组,包含对象自身的所有Symbol 属性的键名
- Reflect.ownKeys(obj) - 返回一个数组,包含对象自身的(不含继承的)所有键名,不管键名是Symbol或字符串,也不管是否可枚举。
它们都遵循
-
首先遍历所有数值键,按照数值升序排序
-
其次遍历所有字符串键,按照加入事件升序排序
-
最后遍历所有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() - 用于对象的合并
- 实行的浅拷贝
- 同名属性直接替换
- 可以处理数组,但是会把数组视为对象
- 如果复制取值函数,那么将求值后再复制
- Object.getOwnPropertyDescriptors() - 返回某个对象属性的描述对象(descriptor)
- __proto__属性,Object.setPrototyprOf() ,Object.getPrototyprOf()
- Object.keys(),Object.values(),Object.entries()
- Object.fromEntries() - 是Object.entries()的逆操作,用于将一个键值对数组转为对象
运算符的扩展
- ** - 指数运算符(当有多个指数运算符时,先计算最右边的再往左计算)
- ?. - 链判断运算符 判断左侧的对象是否为null或者undefined。如果是,就不再往下计算,而是返回undefined
-
obj?.prop //对象属性是否存在
-
obj?.[expr]//同上
-
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 表示独一无二的值,主要是解决对象属性名可能会相同导致冲突的情况。