1、let和const
let使用注意:作用域只在当前代码块,变量不会提升(暂时性死区),相同作用域不能重复声明,for循环体现父子作用域
const使用注意:作用域只在当前代码块,变量不会提升(暂时性死区),相同作用域不能重复声明,声明即需赋值不能改(对象属性值可修改)
2.块级作用域:
<1>外层作用域无法读取内层,内层可以定义外层同名作用域
<2>ES5函数只在顶层作用域和函数作用域内申明
ES6浏览器,块级作用域允许申明(只有在使用大括号的),申明类似var,会提升(行为差异大,尽量避免或者用函数表达式)
<3>do表达式: let x=do{ return 'wtf?0 0' } 可以返回块级作用域的返回值(提案)
3.解构赋值
<1>等号右边具有 Iterator 接口,就可以一一对应赋值(Iterator 接口:数组、某些类似数组的对象、Set和Map结构)
<2>等号左边允许设置默认值:let [y=1]=[] (===undefine 才生效)
<3>默认值如果是表达式,惰性求值,即只有需要生效的时候才求值
<4>对象解构,变量和属性名对应,不用一一对应,否则就需要
<5>左边为对象,右边字符串,转成类似数组对象,数字和布尔值,转成对象,null和undefined无法转,报错
<6>函数解构,默认值是参数对象的默认值,move({x,y}={x:0,y=0}) ,当move({}),x,y都为undefined;当move(),默认值生效
<7>三种不能使用()的情况:变量声明语句:let [(a)]=[1];函数参数:function f( [(z)] ){ return z;} ;赋值语句的模式:( [a] )=[5]
<8>赋值语句的非模式:[ (a) ]=[3];
4.字符串扩展(字符在JS以UTF-16格式储存,2字节/字符)
<1>字符的 Unicode 表示法:’\u{lF680}’===’\uD83D\uDE80 ’ (即将码点放进大括号就与四字节UTF-16等价)
<2>charAt(index)以单字符字符串的形式返回给定位置的那个字符。
chatCodeAt(index)返回给定位置的那个字符的字符编码。
codePointAt (index) 能处理4字节的字符,返回的是给定位置的字符的十进制码点(二字节的字符,返回同chatCodeAt) ----ES6 --定义在字符串实例对象上
<3>String fromCharCode()不能识别 32 位的 UTF 16 字符( Unicode 编号大于 OxFFFF )--ES5
String fromCodePoint()能,多个参数的时候会被合并成一个字符串返回---ES6 --定义在string对象上
<4>normalize() 统一不同表示的字符的形式:’ \ u01Dl ’ . normalize() === ’ \ u004F \ u030C ’. normalize ()
有四个参数:NFC,NFD,NFKC,NFKD(需要则查)
<5>确定一个字符串是否包含在另一个字符串:indexOf
新增:都支持第二个参数,便是开始搜索的位置
includes():返回Boolean;
startsWith():返回Boolean,是否在源字符串的头部,第n到结束
endsWith():返回Boolean,是否在源字符串的尾部,前n个字符是否存在指定字符串
<6>repeat(num),将字符重复num次返回新字符串,取num的整,为负数或者Infinity报错。num为字符串先转化数字
<7>padStart(),padEnd():头尾补全,参数一指定字符串最小长度;参数二用来补全的字符串(‘’则用空格补全 )
用途:数值补位:100000;提示字符串格式:‘12’.padStart(10,’YYYY-MM- DD ’ ) // ” YYYY- MM- 12 ”
<8>模板字符串:‘html代码’ ,中间如果有变量等:${变量或者表达式或者函数调用};中间如果有反引号(‘), \ 转义。
中间的空格和换行将被保留。模板中的变量可以嵌套另一个模板
<9>标签模板:函数后面跟字符串模板:alert '123' === alert(123)
可以过滤HTML字符串,防止恶意内容(通过获取变量转化),同时标签模板中的js语言中可以嵌入其他语言(还可以再深入了解)
<10>String.raw:变量替换,并对反斜线进行转义(如果已转就不处理),作为正常函数(不理解???)
5.正则扩展
<1>u修饰符,增加之后可以处理4字节的UTF-16编码:/<\uD83D/u . test (’\uD83D\uDC2A ’) I I false
大括号表示 Unicode 字符的表示法,必须加上u,否则会被解读为量词:
/ \ u{61}/.test (’ a ’) //false
/ \ u{61}/u.test (’ a ’) //true
<2>y 修饰符:全局匹配,默认匹配的值前面有个隐藏的^(即从头匹配),遵循lastIndex属性。
<3> 正则对象多了sticky属性,表示是否设置了y修饰符,值为Boolean;
新增flags属性,会返回正则的修饰符(source是ES5返回正则的正文)
<4> 先行断言(支持,eg:x在y前才匹配)和后行断言(反之)
<5>了解:\p{ ... }和\P { ... },允许正则表达式匹配符合 Unicode 某种属性的所有
字符,比如指定匹配希腊字符什么的,需要再深入了解
<6>具名组匹配:
/(\d{4})-(\d{2})-(\d{2})/ ===》/ (?
?<组名>(匹配)。 然后拿的时候arr.groups.组名 arr为匹配结果
6.数值扩展
<1>ES6 提供 进制和八进制数值的新写法,分别用前缀 0b(0B)和 0o(0O)表示。要转成十进制,用Number(str)
<2>全局的isFinite(),isNaN() 和 Number.isNaN,Number.isFinite的区别:
前者先将非数值转为数值再进行判断,后者只对数值有效,非数值一律返回false
<3>全局方法parseInt ()和 parseFloat ()移植到了 Number 对象上面
<4>Nurnber.islnteger() 用来判断 个值是否为整数。JS内。3和3.0为同一个值。
<5>Number.EPSILON 的实质是 个可以接受的误差范围,浮点数运算是不精确的。
<6>js的极限值2的53次方,超出值仍未2的53次方
ES6 引入了 Number.MAX_SAFE_INTEGER Number.MIN_SAFE_INTEGER 两个常
用来表示这个范围的上下限,Number.isSafeInteger ()来判断是否落在这个范围内
Number.MAX SAFE INTEGER === Math.pow(2, 53) - 1
<7>Math对象上新增函数(非数转数,转不了NaN)
Math.trunc(): 去除小数部分;
Math.sign(): 判断是否未正数(+1),负数(-1),0(0,-0);
Math.cbrt():算立方根
Math.clz32(): 返回一个数的32位无符号整数形式有多少个前导0 ------(再说)
Math.imul(): 返回两个数以 32 位带符号整数形式相乘的结果,返回的也是 32的带符号整数。 ------(再说)
Math.fround(): 返回回最接近这个小数的单精度浮点数。 ------(再说)
Math.hypot(): 返回所有参数的平方和的平方根。
Math.expml (x)返回 ( -1) ,即 (Math.exp(x) -1) 。
Math.log1p(x)返回 ln(1+x) ,即 Math.log(1+x) 。
Math.log10(x)返回以 10 为底的 x的对数。如果x 小于 0,则返回 NaN
Math.log2(x)返回以 2 为底的 x的对数。如果x 小于 0,则返回 NaN
新增(**):a **=2 即位a的平方,3则为3次方
<7>提案:Integer数据类型(JS 所有数字都保存成 64 位浮点数,所以大于一定范围无法精确表示,不合适进行科学和金融的精确计算),只用来表示整数,没有位数限制,为了和Number类型区分,数据后面都必须加n:
例子: 1n+2n===3n 0b1101n //二进制 0o777n //八进制 0xFFn //十六进制
运算: + - * **四个同Number 。除法的话只返回整数部分。不能同Number类型数据混合运算
7.函数扩展
<1>函数参数设置默认值,应该是放在尾部,如果不是放在尾部,则说明这个参数是必传的,如果不传或者null报错,undefined可以,因为会触发默认值。
<2>函数指定默认值后,(fun(){}).length 返回的是没有默认值的参数个数,即失真。如果设置默认参数的不是尾参数,那么后面的参数也不计入length。
<3>函数设置参数默认值,相关作用域
let x=1;
function wwww (x, y=x){
let x=3;
console.log(y)
}
www2(2); //2
这里参数y=x,x指向的是第一个参数。如果没有参数x,x就没有定义,y=x的时候,x指向外面的那个x=1,如果外面的x不存在则会报错
<4>rest参数(...参数名):参数名是一个数组,它把所有参数放进该数组
<5>ES6规定函数参数只要使用了默认值,解构赋值或者扩展运算符,那么函数内部不能使用‘use strict’,否则报错。原因再看
<6>函数的name属性:fun.name返回该函数的函数名,如果匿名函数赋值给一个变量,ES5返回空字符串,ES6返回该变量名。
如果具名函数赋值给变量,还是返回函数名。
构造函数返回的函数实例,name的值为anonymous
bind返回的函数,返回的函数名前面 + bound。
<7>箭头函数的注意事项
1.不能使用arguments参数,可以使用rest参数代替
2.不能使用yield命令,因为不能作用于Generator函数
3.箭头函数无this,所以call,bind,apply这些方法无法使用去改变this
<8>尾部调用:函数的最后一步是调用另一个函数,即return fun(x),如果不是return,则还有一步return undefined
目的是,尾调用优化,函数调用会形成一个调用帧,如果尾调用不会用到外层函数的变量,这样就会只保留这个内部函数的调用帧,节省内存
重要运用,尾递归(ES6严格模式,其他可用循环代替,用一个状态)
8.数组扩展
<1>扩展运算符:...[数组],类似于rest参数,把数组变成以逗号分隔的参数序列,不仅应用在函数参数,还可以应用在其他地方
运用:1.扩展符与解构结合:const [first, ...rest] = [1 , 2 , 3 , 4 , 5]; //1,[2,3,4,5]
注意:...rest依旧只能放在最后一位,否则报错。
2.32为Unicode字符会被js识别为2个字符,用扩展(...字符串)则可以正确识别长度
3.具有Iterator接口的对象,可以使用扩展运算符
<2>Array.from()方法:可以将类数组对象(eg:DOM操作返回的NodeList集合,arguments对象,,本质特征是有length属性)和可遍历对象(Set和Map数据结构) 转为真正的数组;
Array.from(arrayLike , x => x*x) 第二个参数作用类似数组map方法,会把每个元素进行处理,如果map方法中用到this,则还可以传入第三个参数用来绑定this
<3>Array.of()方法:将一组值转成数组
因为Array(3) //[,,,] 而不是[3] 所以可以用Array.of()来代替
<4>copyWithin(开始替换的位置,读取的开始位置,读取结束位置),第一个参数必传,如果有负,则倒着数
eg:[ 1, 2 , 3 , 4, 5 ]. copyWithin( 0 , 3 , 4) // [ 4, 2 , 3 , 4, 5 ]
<5>find和findIndex()用于数组中寻找第一个符合的元素,前者找到返回值,找不到undefined;后者返回index/-1
<6>fill()用来填充一个数组: [ 数组 ].fill(填充的值,填充初始位置,填充结束位置)
eg: [ ’ a ’,’b ’,’ c ’ ]. fill (7) //[ 7,7,7]
<7>entries()、 keys()和 values()遍历数组,分别是对键值对,键名,键值的遍历
<8>includes():数组中是否包含给定值,返回Boolean,而indexOf()找的是index,而且判断的时候使用===,会导致对NaN的误判;Set和Map结构有个has方法,前者用来找值,后者用来找键名
<9>数组中的空位,在ES5,ES6,不同方法的处理(需要再查),可能会被视为undefined,也有会被忽略,所以进来避免出现空位
9.对象扩展
<1>简洁表达式:ES6允许在对象中只写属性名,属性值等于属性名所代表的变量,写入方法也一样:
{ funName () { console.log ('略略略') } } // { method: fun(){} }
如果写入的方法值是一个Generator函数,则要在名字前加上星号
<2>属性名表达式:在定义对象的时候,可以用表达式作为对象的属性名(把表达式放在[ ]内),eg:
let test='emmm';
let obj={
[test]:true,
['a'+'bc']:123
}
obj[test] //true
obj['emmm'] //true
obj['abc'] //123
注意:属性名表达式合简洁表达式不能同时使用,否则会报错;属性名表达式如果是一个对象,默认转为字符床[ object , Object ]
<3>方法Object.is()传入要比较的两个值,返回Boolean,与===的区别在于,该方法+0!== -0 以及NaN等于自身
<4>Object.assign() 方法第一个参数是目标对象,后面可传入n个源对象,它会将源对象所有可枚举的属性复制到目标对象上,同名则后覆盖前。
如果参数不是对象,则先转为对象,如果无法转为对象,则会被跳过。
注意:1.该方法是浅复制,即复制对象的值如果是个对象,则复制的是这个对象的引用,键名同名会被替换,小心
2.如果用来处理数组,会把数组视为对象来处理
常见用途:1.为对象添加属性; 2.为对象添加方法; 3.克隆对象(只能克隆本身的值) 4.合并对象 5.设置默认值
<5>属性的可枚举性:对象每个属性都有一个Descriptor,用来控制该属性的行为,用Object.getOwnPropertyDescriptor(对象名,'属性名'),获取到:{ value:xxx, writable:true, enumerable:true(可枚举性), configurable:true }
for...in, Object.keys(), JSON.stringify(), Object.assign() 会忽略enumerable为false的属性
<6>5种属性的遍历的方法
1. for...in:遍历循环对象自身和继承的可枚举属性,不含Symbol属性
2. Object.keys(obj):返回一个数组,包括自身所有可枚举属性名
3. Object.getOwnPropertyName(obj):返回一个数组,包含对象自身所有属性,不含Symbol属性,但包含不可枚举的属性
4. Object.getOwnPropertySymbols(obj):返回一个数组,包含对象自身所有的Symbol属性
5. Reflect.ownKeys(obj):返回一个数组,包含对象自身的所有属性,不管是Symbok还是字符串,不管是否可枚举
遍历原则:a:属性名为数值的,按数字排序 ;b:属性名为字符串的,按生成时间排序;c:属性名为Symbol值的属性,按生成时间排序
<6>原型属性_proto_:无论从语义角度和兼容性角度,都不要直接使用,而是用
Object.setPrototypeOf() 写,设置对象的prototype属性,返回参数对象本身
Object.getPrototypeOf() 读
Object.create() 生成
读和写的第一个参数为对象,如果不是对象将转为对象,返回的是第一个参数本身;写的第二个参数是要传的内容
<7>对象的扩展运算符(...)
解构赋值(不会复制原型对象的属性):let {x,...y}={ x:1, y:2, a:3} y// { y:2, a:3}
<8>Object.getOwnPropertyDescriptors() ES6:获取对象所有自身的描述。返回的是一个对象,键名同参数对象键名,值为描述。ES5有Object.getOwnPropertyDescriptor()------不带s,是对象的单个某个属性描述,第一个参数也是一个对象,第二个参数为键名。引入的原因是Object.assign()无法争取复制get和set属性(因为该方法总是复制一个属性的值,而不会复制它背后的取值方法或赋值方法)。所以正确复制如下:
const combineObj= (target, source) => Object.defineProperties(
target,
Object.getOwnPropertyDescriptors(source)
<9>一个提案:Null传导运算符
当获取message.body.user.firstName的值的时候,如果body不存在则会报错。所以不用层层判断,提案简写:
message?. body?. user?.firstName 只要其中一个返回null或者undefined就不再往下,返回undefined