ES6新语法特性(第二篇)
在上一篇讲了let声明变量,const声明常量,解构赋值,模板字符串,对象简化写法,箭头函数,这篇继续概述ES6其他的新特性。
主要包括以下内容:
1)函数参数默认值设定及与解构赋值的结合使用;
2)rest参数替代arguments处理可变参数;
3)扩展运算符在函数调用、数组合并和伪数组转换中的应用;
4)Symbol数据类型创建唯一标识符及其特性;
5)Set集合实现数组去重、交并差集运算;
6)Map数据结构扩展键值类型;
7)数值扩展和对象方法扩展;
8)模块化及导出方式
9)私有属性
一、函数参数默认值
Es6允许给函数的形参设置初始值(默认值),如果传参,会覆盖默认值。写的时候,具有默认值的参数,一般位置放后边。
javascript
function add(a,b,c=10){
return a +b + c
}
let result1 = add(1,2) // c未传参,默认为10
let result2 = add(1,2,3) // c传参,值为3
console.log(result1) // 13
console.log(result2) // 6
默认值可以与解构赋值结合使用:
javascript
//传统写法
//每次都要people.去获取对象的值,不简洁
function fn(people){
console.log(people.name) //张三
console.log(people.age) //18
console.log(people.like) //study
}
fn({
name : '张三',
age:20,
like:'study'
})
//解构赋值 + 默认值
function fn({name,age,like,sex = '男'}){
console.log(name) //张三
console.log(age) //18
console.log(like) //study
console.log(sex) //男(默认值)
}
二、rest参数(...args
)
arguments
是JavaScript函数内部的一个特殊对象,它包含了调用函数时传递的所有参数。这个类数组对象在ES5及之前版本中广泛用于处理可变数量参数。
但在现代JavaScript开发中,ES6的剩余参数(...args
)已成为更推荐的替代方案。
javascript
function data(){
console.log(args)
}
data('香蕉','苹果','梨') //{'香蕉','苹果','梨'}--->对象
//rest参数
function data(...args){
console.log(args)
}
data('香蕉','苹果','梨') //['香蕉','苹果','梨']--->数组
返回了一个数组,这样可以使用数组的filter,some,every,map等api方法,提高了对参数处理的一个灵活程度。
注意:语法上,rest参数必须放在最后!
三、扩展运算符
javascript
const fruit = ['香蕉','苹果','梨']
function fn(){
console.log(arguments)
}
const fruit = ['香蕉','苹果','梨']
fn(...fruit) // 等同于-->fn('香蕉','苹果','梨'),将数组'展开'了
//用法一:数组合并
const vegetable = ['黄瓜','西红柿','胡萝卜']
//传统写法
//const food = fruit.concat(vegetable)
const food = [...fruit,...vegetable]
console.log(food) // ['香蕉','苹果','梨','黄瓜','西红柿','胡萝卜']
//用法二:数组克隆(若拷贝数组里有引用类型对象,这里是浅拷贝,新旧对象指向同一地址)
const shuiguo = [...fruit] // ['香蕉','苹果','梨']
//用法三:将伪数组转为真数组
const divs = document.querySelectorAll('div') //伪数组
const divArr = [...divs]
console.log(divArr) //是一个真数组
区分rest参数和扩展运算符:
rest的位置是函数声明的形参位置,而扩展运算符是在函数调用的是实参中。
rest:function data(...args){ }
扩展运算符:fn(...fruit)
四、Symbol基本使用
Symbol是JavaScript中一种特殊的原始数据类型,自ES6引入,是js语言的第七种数据类型,类似于字符串,主要用于创建唯一且不可变的标识符。
1. 特点:
-
Symbol值是唯一的,用来解决命名冲突的问题。
-
Symbol值不能与其他数据进行运算。
-
Symbol定义的对象属性不能使用for...in遍历循环,但是可以使用Reflect.ownKeys来获取对象所有键名。
-
Symbol不能与其他类型隐式转换,但可以显式转换为字符串或布尔值:
javascriptconst sym = Symbol('foo'); // 隐式转换会报错 // 'sym value is: ' + sym; // TypeError // 显式转换 String(sym); // "Symbol(foo)" Boolean(sym); // true Number(sym); // TypeError
-
Symbol.prptotype.description 获取Symbol的描述字符串
javascriptlet s = Symbol('John') console.log(s.description) //John
五、set集合
ES6提供了新的数据结构Set(集合),它类似于数组,但成员的值都是唯一的,集合实现了iterator接口,所以可以使用扩展运算符和 for...of... 进行遍历集合的属性和方法。
for i in list
遍历的时候,i 代表数组索引值,
foe i of list
遍历的时候,i 代表该索引下标对应的值。
set的属性和方法:
(1)size 元素个数 set.size
(2)add ()添加新元素 set.add(str)
(3)delete() 删除某个元素 set.delete(str)
(4)has ()查找某元素 set.has(str)
(5)clear ()清空集合 set.clear()
(6)for(let i of set) { } 遍历集合中的值
set的应用
(1)数组去重
把数组new为set集合实例,然后用展开运算符展开集合,并用数组[ ]包住。
javascript
let arr = [1,2,3,4,1,2,3]
let result = [...new Set(arr)] // [1,2,3,4]
(2)求两个数组的交集
两个数组去重后,遍历数组1的元素,判断集合2中是否有数组1的元素
javascript
let arr1 = [1,2,3,4,1,2,3]
let arr2 = [3,4,5,3,4]
let res1 = [...new Set(arr1)] //[1,2,3,4]
let res2 = new Set(arr2) //{3,4,5}
let res = res1.filter(item => {
if(res2.has(item)){ //has方法是集合的方法
return true
}else{
return false
}
})
console.log(res) //[3,4]
//可以简化为一行代码
let res = [...new Set(arr1)].filter(item => new Set(arr2).has(item))
(3)求两个数组的并集
将两个数组通过展开运算符合并为一个数组后,去重s
javascript
let arr1 = [1,2,3,4,1,2,3]
let arr2 = [3,4,5,3,4]
let res = [...new Set([...arr1,...arr2]) ] //[1,2,3,4,5]
(4)求两个数组的差集
javascript
let res = [...new Set(arr1)].filter(item => !(new Set(arr2).has(item))) //取反,交集的逆运算
六、Map集合
ES6提供了Map数据结构,它类似于对象,也是键值对的集合,但是'键'的范围不局限于字符串,各种类型的值都可以(包括对象)当作键。Map也实现了iterator接口,所以可以使用扩展运算符和 for...of... 进行遍历。可以理解map为升级版的对象。
Map的属性和方法:
javascript
//声明Map
let m = new Map()
//添加元素
m.set('name','张三')
m.set ('eat',function(){
....函数体
})
//Map的元素个数
console.log(m.size)
//删除元素
m.delete('name') //通过键名删除
//获取查找某元素
m.get('eat') //通过键名获取value值
//清空Map
m.clear()
//遍历Map
for(let v of m){
console.log(v)
}//遍历获取value值
七、ES6数值扩展
(1)Number.EPSILON( )
Number.EPSILON是JavaScript表示的最小精度,属性值接近于2.22004460...E-16,如果两个值的差小于该精度,可以认为这两个值相等。
javascript
//如果两个值的差小于该精度,认为这两个值相等
function equal(a,b){
if(Math.abs(a-b) < Number.EPSILON){
return ture
}else{
return false
}
}
console.log(0.1 + 0.2 === 0.3) //false
console.log( equal(0.1 + 0.2 , 0.3) ) //true
(2)Number.isFinite( )
检测一个数值是否是有限数。
javascript
console.log(Number.isFinite(100)) //true
console.log(Number.isFinite( 100/0 )) //false
(3)Number.isNaN( )
检测一个数值是否是NaN。
javascript
console.log(Number.isNaN(100)) //false
(4)Number.parseInt / Number.parseFloat( )
字符串转整数。
javascript
console.log(Number.parseInt(100156love)) //100156
console.log(Number.isFlost(1.13154abc)) //1.13154
(5)Number.isInteger( )
检测一个数是否是整数。
javascript
console.log(Number.isInteger(5)) //true
console.log(Number.isInteger(5.5)) //false
(6)Math.trunc( )
将数字的小数部分抹掉。
(7)Math.aign( )
判断一个数到底为正数,负数,0。
正数返回1,负数返回-1,0返回0。
(8)进制数表示
0b开头表示二进制数,0o开头表示八进制数,0x开头表示十六进制数。
八、对象方法扩展
(1)Object.is
判断两个值是否完全相等。
javascript
console.log(Object.is(1,1)) //true
console.log(Object.is(NaN,NaN)) //true 通过object.is判断,NaN是相等的
console.log(NaN === NaN //false
2.Object.assign
对象的合并。
javascript
Object.assign(obj1,obj2)
//两个对象进行合并,合并为一个对象,若出现重名,obj2会覆盖和obj1同名的属性
3.Object.setPrototypeOf(obj1,obj2)
设置原型对象,把obj2设置为obj1的原型对象。但推荐在创建对象时就设置好其原型对象。
4.Object.getPrototypeOf(obj1)
获取obj1的原型对象。
5.Object.entries
- 返回一个由对象自身可枚举属性的键值对组成的二维数组,格式为
[ [key1, value1], [key2, value2] ]
。 - 即把对象变为一个数组,数组元素是把对象里的每组键值对写成一个数组。这样可以实现将对象转变为map。
- 浅拷贝:返回的数组是原对象属性的副本,修改数组中的值会影响原对象。
- 不包含继承属性:仅处理对象自身的可枚举属性,忽略原型链上的属性
javascript
const p = {
name:'John',
hobby:['eat','study','sleep']
}
//获取对象所有键
console.log(Object.keys(p))//['name','hobby']
//获取对象所有值
console.log(Object.values(p))//['John',Array(3)]
// entries
console.log(Object.entries(p))
// 输出结果:
[Array(2),Array(2)] 返回一个新数组
> 0: ['name':'John'] 数组每个元素 :是对象键值对写成数组
> 1: ['hobby',Array(3)]
const m = new Map(Object.entries(p))
console.log(m)
// 输出结果:
Map(3){'name':'John','hobby' => Array(3)}
6.Object.fromEntries
与Object.entries相反(逆运算),它可以把键值对组成的二维数组转为一个对象。
javascript
const res = Object.fromEntries([
['name':'John'],
['hobby',Array(3)]
])
console.log(res) // { name:'John',hobby:['eat','study','sleep']}
7.Object.getOwnPropertyDescriptors( )
该方法返回指定对象所有自身属性的描述对象
九、ES6模块化
ES6模块化是ES6标准中引入的原生JavaScript模块化方案,旨在解决大型项目中代码组织、依赖管理和复用性问题。其核心是通过export
和import
关键字实现模块的导出与导入,将代码拆分为独立的、可复用的模块。以下是ES6模块化的关键特性和要点:
核心特点
- 独立作用域:每个模块拥有独立的作用域,内部变量和函数默认不会污染全局命名空间,避免了命名冲突。提高代码复用,高维护性。
- 静态化加载:模块的依赖关系在编译时确定(静态分析),而非运行时动态加载,这使得工具能够优化代码(如Tree Shaking)并提升性能。
- 显式导出与导入 :通过
export
导出模块的变量、函数或类,其他模块通过import
按需引入,形成清晰的依赖关系。
在ES6模块化规范里,共有三种暴露方式,分别是分别暴露、统一暴露和默认暴露,下面展开介绍:
1.分别暴露
- 语法 :在需要暴露的变量、函数、对象等前面直接使用
export
关键字。 - 特点:可以导出多个具名成员,导入时需使用确切名称。
- 示例:
javascript
// 分别暴露
export const person = {name: 'zhangsan', age: 12};
export function playGame() {
console.log('打游戏');
}
2.统一暴露
- 语法 :先在模块内部定义变量、函数等,最后使用
export {变量名1, 变量名2...}
的形式统一导出。 - 特点:与分别暴露类似,但导出列表集中管理,提高代码可读性,适合模块内部定义较多,但只需要暴露部分内容的场景,便于维护和管理导出接口。
- 示例:
javascript
// 统一暴露
const cat = {name: 'xiaotao', age: 5};
function playBall() {
console.log('猫咪喜欢玩球');
}
export {cat, playBall};
3.默认暴露
- 语法 :使用
export default
,后面可以跟变量、函数、对象等,每个模块只能有一个默认导出。 - 特点:导入时可自定义名称。
- 示例:
javascript
// 默认暴露
export default function A() {
console.log('你好');
}
三种暴露方式在导入时也有所不同:
-
分别暴露和统一暴露导入时使用
import {变量名1, 变量名2} from '模块路径'
。(解构赋值的方式引入) -
默认暴露导入时使用
import 自定义名称 from '模块路径'
。 -
若引入多个模块,有方法发生重名,可以在引入时通过as定义别名。
import {apple as pingguo} from './....'
import {default as pingguo} from './....'
十、私有属性
类私有字段是 ES2020 引入的官方标准方法,通过在属性名前加 #
前缀来定义私有属性。
js
class Person {
#name; // 私有属性声明
constructor(name) {
this.#name = name;
};
getName() {
return this.#name;
};
setName(newName) {
this.#name = newName;
}
}
const person = new Person('John');//实例化
console.log(person.getName()); // "John"
console.log(person.#name); // SyntaxError: 私有字段无法外部访问