ES6的新特性(3)
一、解构表达式
解构赋值是对赋值运算符的扩展。它是一种针对数组或者对象进行模式匹配,然后对其中的变量进行赋值。
字符串、以及ES6新增的Map和Set 都可以使用解构表达式
//数组解构
let [a,b,c] = [1,2,3];
console.log(a,b,c); //1,2,3
let [a,b,c] = [1,,3];
console.log(a,b,c); //1,undefined,3
let [a,,b] = [1,2,3];
console.log(a,b);//1,3
let [a,..b] = [1,2,3]; //...是剩余运算符,表示赋值运算符右边除第一个值外剩余的都赋值给b
console.log(a,b);//1,[2,3]
//对象解构
let obj = {
name: "ren",
age: 12,
sex: "male"
};
let { name, age, sex } = obj;
console.log(name, age, sex); //'ren' 12 'male'
let { name: myName, age: myAge, sex: mySex } = obj; //自定义变量名
console.log(myName, myAge, mySex); //'ren' 12 'male'
二、Map和Set
Map对象用于保存键值对,任何值JavaScript支持的值都可以作为一个键(key)或者一个值(value)。
与对象不同的是
- object的键只能是字符串或ES6的symbol值,而Map可以是任何值。
- Map对象有一个size属性,存储了键值对的个数,而object对象没有类似属性。
Set
可以理解为后端的Set集合对象
- Set对象和Map对象类似,但它存储不是键值对。类似数组,但它的每个元素都是唯一的。
- 利用Set对象唯一性的特点,可以轻松实现数组的去重
//Map对象
let myMap = new Map([['name','ren'],['age',12]]);
console.log(myMap); //{'name'=>'ren','age'=>12}
myMap.set('sex','male');
console.log(myMap); //{'name'=>'ren','age'=>12,'sex'=>'male'}
console.log(myMap.size); //3
myMap.get('name'); //'ren'
myMap.has('age'); //true
myMap.delete('age'); //true
myMap.has('age'); //false
myMap.get('age'); //undefined
//set对象
let mySet = new Set([1,2,3]);//里面要传一个数组,否则会报错
console.log(mySet); //{1,2,3}
mySet.add(4);
console.log(mySet); //{1,2,3,4}
mySet.delete(1); //true
mySet.has(1); //false
console.log(mySet); //{2,3,4}
三、其他改动
3.1…(扩展运算符)
//用于拷贝
<script>
let person={
name: "admin",
age: 12,
wife:"迪丽热巴"
}
let person2={...person}
console.log(person2===person);//false
console.log(person2);//{name: 'admin', age: 12, wife: "迪丽热巴"}
</script>
//合并对象
<script>
const obj1 = { a: 1 };
const obj2 = { b: 2 };
const obj3 = { a: 5, c: 3 };
let newObj ={...obj1,...obj2,...obj3}
console.log(newObj); // { a: 5, b: 2 , c:3}
</script>
3.2 箭头函数
箭头函数实现了一种更加简洁的书写方式。箭头函数内部没有arguments,也没有prototype属性,所以不能用new关键字调用箭头函数。
并且箭头函数和普通函数最大的区别在于其内部this永远指向其父级对象的this。
let add = (a,b) => {
return a+b;
}
let print = () => {
console.log('hi');
}
let fn = a => a * a;
//当只有一个参数时,括号可以省略,函数体只有单行return语句时,大括号也可以省略。
//------------------------------------------------------------------
var age = 123;
let obj = {
age:456,
say:() => {
console.log(this.age); //this指向window
}
};
obj.say(); //123
3.3 class类
class 作为对象的模板被引入ES6,你可以通过 class 关键字定义类。class 的本质依然是一个函数。
<script>
//创建类
class person {
//关键字声明方式
constructor(name) {
this.name=name
}
say() {
console.log("hello");
}
}
var p = new person('p');
p.say(); //'hello'
console.log(p.name);
</script>
//类的继承
**<script>
class Person {
constructor(name, age) {
this.name = name;
this.age = age;
}
say() {
console.log(this.name + ":" + this.age);
}
}
class Student extends Person {
constructor(name, age, sex) {
super(name, age);//类的继承通过extends关键字实现。子类必须在constructor中调用super()
this.sex = sex;
}
}
var student = new Student("admin", 12, "male");
student.name; //'admin'
student.sex; //'male'
student.say(); //'ren:12'
</script>
**
3.4 promise和proxy
promise
Promise 是异步编程的一种解决方案,简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。从语法上说,Promise 是一个对象,从它可以获取异步操作的消息。Promise 提供统一的 API,各种异步操作都可以用同样的方法进行处理。
Promise对象有以下两个特点。
- 对象的状态不受外界影响。
- 一旦状态改变了就不会再变,也就是说任何时候Promise都只有一种状态。
Promise有三种状态,分别是 Pending (进行中)、Resolved (已完成)、Rejected (已失败)。Promise从Pending状态开始,如果成功就转到成功态,并执行resolve回调函数;如果失败就转到失败状态并执行reject回调函数。
//通过Promise的构造函数创建Promise对象
var promise = new Promise((resolve,reject) => {
setTimeout(()=>{
console.log("hello world")
}, 2000)
})
Promise构造函数接受一个函数作为参数,该函数的两个参数是 resolve ,reject。其中 resolve 函数的作用是当Promise对象转移到成功,调用resolve并将操作结果作为其参数传递出去;reject 函数的作用是当Promise对象的状态变为失败时,将操作报出的错误作为参数传递出去。
function greet(){
var promise = new Promise(function(resolve,reject){
var greet = "hello world"
resolve(greet)
})
return promise
}
let test = greet().then(v=>{
console.log(v)//1
//v值为resolve传递出来的参数,也就是greet。
})
console.log(test)//2
//最终上述打印结果为注释1行先打印,而后到注释2行,打印结果为
//Promise {<pending>}
//hello world
上述例子也可以看出promise执行then还是一个promise,且promise的执行是异步的,根据这一特性就可以不断的链式调用回调函数连then
更多promiseAPI可以查阅https://es6.ruanyifeng.com/#docs/promise
Proxy
Proxy 可以理解成,在目标对象之前架设一层“拦截”,外界对该对象的访问,都必须先通过这层拦截,因此提供了一种机制,可以对外界的访问进行过滤和改写。
// 代理是什么呢?
// 比如下面,通过proxy这个中间人来获取对象里的内容,中间人就是代理
// 首先定义一下对象
let user={
name:"小明",
age:10
}
// 下面就是使用代理
// 首先 let a = new Proxy(obj,{}) obj代表代理得目标对象
// 后面得对象代表得是使用get方法和set来获得值和设置值
let a = new Proxy(user,{
// get方法里面第一个参数传代理目标对象target源对象也就是上面的user,第二个代表读取的属性
get(target,attr){
console.log(target); // user
console.log(attr); // age,因为下面调用a的时候,使用的是age属性
// return里面的内容就是读取user时的返回值,可用reflect反射对象代理
return target[attr]?target[attr]:null
},
// set方法里面第一个参数传代理目标对象target源对象,第二个代表属性,第三个代表设置的值
set(target,attr,value){
target[attr] = value
}
})
let age = a.age
//----------------------例如
const obj = {
a: 10
}
let handler = {
get: function(target, attr){
console.log('test: ', target, attr)
// test: {"a":10} a
// test: {"a":10} b
return attr in target ? target[attr] : 37 //in 如果指定的属性在指定的对象或其原型链中,则 in 运算符返回 true。
}
}
let p = new Proxy(obj, handler)
console.log(p.a, p.b) // 10 37
上诉例子还用到了in操作符,其中in操作符:如果指定的属性在指定的对象或其原型链中,则 in 运算符返回 true。且in的右操作数必须是一个对象值。例如,你可以指定使用 String 构造函数创建的字符串,但不能指定字符串文字。
3.5 模块化
es6中新增的模块化很好的防止了命名冲突,并且复用性强。
//导入 ES6使用关键字 import 导入模块(文件),有两种常用的方式:
import ‘模块名称’ from ‘路径’;
import ‘路径’;
//导出
let name = 'ren',age = 12;
export {name,age};
//注意:变量需要用大括号包裹,然后才能向外输出