带你了解ES6中的一些新特性

332 阅读6分钟

这是我参与更文挑战的第十一天,活动详情查看: 更文挑战

let 和 const

let: 声明的变量只有在let命令下的代码块有效,也叫块级作用域

const: 声明的变量是只读的,一旦声明常量的值就不能改变,

但是如果用const来声明数组或者对象,则数组,对象下的值可以改变,原因是const指向的变量的地址没有发生改变

let 和 var的区别

  1. let是在代码块内有效,var是全局范围有效
  2. let只能声明一次,var可以多次声明;
  3. let不存在变量提升,但有作用域链

解构赋值

从数组和对象中提取值,对变量进行赋值,称为解构赋值

  1. 基本的数组对数组赋值
let [a,b,c] = [1,2,3];//a=1,b=2,c=3
  1. 采用剩余运算符
let [a,...b] = [1,2,3];//a=1,b=[2,3]

剩余运算符表示用b来接收之后的所有值,所以返回数组

  1. 字符串解构
let [a,b,c,d,e] = 'hello';//hello

将字符串拆分成一个个字符来赋值,将字符串转化为对象

  1. 对象解构赋值
let {foo, bar} = { foo: 'aaa',bar: 'bbb'};
console.log(foo);//aaa
console.log(bar);//bbb
  1. 变量名和属性名不一致
let { baz : foo} = {baz : 'ddd'}
console.log(foo);//ddd
consolelog(baz);undefind

baz是模式,foo才是值,在解构的时候,内部会先寻找同名的属性,赋值给他,所以这里是foo接收到了ddd

解构赋值应用

交换变量
var a = 1;
var b = 2;
[a,b] = [b,a];
接收返回值
function fn() {
	return [1,2,3];
}
var [a,b,c] = fn();
获取json对象中的数据
var data = {
    name : 'ljc',
    age : 20
}
var {name,age} = data;
console.log(name + age);//ljc20
部分赋值
var ljc=[1,2,3];
var [,x,]=ljc;
console.log(x);//2

var obj = {x : 1,y : 2, z : 3};
var {y : a} = obj;
console.log(a);//2

模板字符串

  1. 引入方式为【``】
console.log(`hello world`);	
  1. 使用模板字符串表示多行字符串,所有的空格和缩进都会被保留在输出之中。
let str = `<ul>
        <li>1</li>
        <li>2</li>
        <li>3</li>
        <li>4</li>
        <li>5</li>
	 </ul>`;
  1. 变量拼接

模板字符串中嵌入变量,需要将变量名写在${}之中

let lovest = 'ljc';
let out = `${lovest}最帅`;
console.log(out);//ljc最帅
  1. 模板字符串调用函数
function fn () {
        console.log('我是ljc');
    }
let out = `${fn()}`;//我是ljc

对象的简化写法

省略同名的属性值,省略方法的function

const name = 'ljc';
const age = 20;
const my = {
    name,
    age,
    say() {
        console.log('我是' + name + '今年' + age);
    }
}
my.say()//我是ljc,今年20

箭头函数

//ES6
let res = () => {
    let a = 3;
    console.log(a);
}
//ES5
var rel = function() {
    var b = 2;
    console.log(b);
}
res();//3
rel();//2
  1. 没有参数时,小括号不能省略
let say = () => {
    console.log('ljc');
}
say();//ljc
  1. 当有一个参数时,小括号可以省略:
let test = a => {
    console.log(a);
}
test('我是ljc');//我是ljc
  1. 当参数大于1个时,小括号不能省略 ()=>{}
let test = (a,b) => {
    console.log(a + b);
}
test(2,3);
  1. 当后面只有一条语句时,大括号可以省略 ,返回值就是这条语句
let say = () => console.log('ljc');
say();//ljc
  • 箭头函数的 this 指向定义时所在的对象

  • 箭头函数没有原型

  • 箭头函数不可以作为构造函数(即不能使用 new)

  • 箭头函数没有 arguments 对象

rest参数

返回值是一个数组,rest参数必须要放到参数最后

function date(...args) {
    console.log(args);
}
date('l','j','c');//['l','j','c']

扩展运算符

将一个数组转化成用逗号分隔的参数列表

function add(x,y) {
	return x + y;
}
let num = [1, 2];
add(...num)//3
应用
function push(array, ...rest) {  
    array.push(...rest);//这个是扩展运算符,将...rest转化成参数列表  
}
let arr =[1,2];
push(arr,3,4,5);
console.log(arr);//[1,2,3,4,5]

Symbol

Symbol能够产生独一无二的值,避免与之前的代码产生覆盖。

传入一个值,作为描述字符串,更好的理解这个值的作用

无论传入的值,参数名是否相同,都是独一无二的

let s1 = Symbol();
let s2 = Symbol();
console.log(typeof s1);// symbol
console.log(s1 === s2); // false
symbol.for创建
let s4 = Symbol.for('ljc');
let s5 = symbol.for('ljc');
console.log(s4 === s5);//true

通过这种方法创建的是可以通过描述字符串得出唯一的symbol

不能与其他数据进行运算

作为属性名
let mySymbol = Symbol();
var a = {};
a[mySymbol] = 'Hello!';
console.log(a);//{ symbol(): 'Hello!' }

Symbol值作为属性名要使用方括号定义,不能使用点运算符

Symbol作为属性名遍历
var obj = {}
var a = Symbol('a')
var b = Symbol('b')
obj[a] = 'a'
obj[b] = 'b'
Object.getOwnPropertySymbols(obj)
//[Symbol(a), Symbol(b)]

使用Reflect.ownKeys可以遍历Symbol的键名

var a = Symbol('a'); 
var b = Symbol('b'); 
var obj = {
    foo: 1
} 
obj[a] = 1; 
obj[b] = 2;
Reflect.ownKeys(obj);
//["foo", Symbol(a), Symbol(b)]

迭代器

迭代器(Iterator)是一种接口,为各种不同的数据结构提供统一的访问机制。任何数据结构只要部署迭代器接口,就可以完成遍历操作。

Iterator接口主要提供for…of消费

工作原理

  1. 创建一个指针对象,指向当前数据的起始位置,返回一个对象(有next方法)
  2. 第一次调用对象的next方法,指针指向数据的第一位
  3. 不断的调用next方法,指针一直向下一位移动,直到指向undefind
  4. 每调用next方法返回一个包含value和done属性的对象
const my = ['ljc','20','men'];
    for(let a of my) {
    console.log(a);
}//ljc 20 men
利用迭代器思想 自定义遍历对象
const my = {
    name: 'ljc',
    age: '20',
    like: ['rose','SaLah','BlackPink'],
    [Symbol.iterator]() {
        let index = 0;//索引变量
        let _this = this;//保存this指向
        return {
            next: function() {
                if(index < _this.like.length) {//判断是否结束
                    const result = {
                        value: _this.like[index],//指向下一个
                        done: false
                    }
                    index++;
                    return result;
                }else {
                    return {
                        value: undefined,
                        done: true
                    }//结束
                }
            }
        }
    }
}
for(let k of my) {
    console.log(k);
}

生成器

拥有在一个函数块内暂停和恢复代码执行的能力

生成器的形成是一个函数,函数名称前面加一个*表示它是一个生成器

/* 生成器函数的声明 */
function* gen() {}
/* 表达式 */
let gen = function* () {}
/* 作为对象字面量方法的生成器 */
let foo = {
    *gen() {}
}
  • 箭头函数不能用来定义生成器函数

  • 星号的位置不影响生成器

调用生成器对象函数会产生一个生成器对象。生成器一开始处于暂停状态,与迭代器相似,生成器对象也实现了iterator接口,具有next方法。因此可以通过调用这个方法来控制生成器的开始或恢复执行

yield中断执行

yield可以让生成器停止或开始执行。生成器函数在遇到yield关键字之前会正常执行。遇到yield后会暂停,通过next方法恢复

function * gen() {
    yield;
}
let genObj = gen();
console.log(genObj.next());// {value: undefined, done: false} yield
console.log(genObj.next());// {value: undefined, done: true} end
生成器对象作为可迭代对象
function* gen() {
            yield 1;
            yield 2;
            yield 3;
}
 for(const x of gen()) {
     console.log(x);
}//1 2 3

注意gen要带括号才是对象

使用yield实现输入输出

yield关键字可以作为函数的中间参数使用。上一次生成器函数暂停的yield会接收到传给next()方法的第一个值。也就是说第一个调用next传入的值不会被使用

function * gen(arg) {
    console.log(arg);//11
    console.log(yield 111); //我是第二个next
    console.log(yield 222);//我是第三个next
    console.log(yield 333);//我是第四个next
}
let iterator = gen(11);
iterator.next('我是第一个next');//启用生成器
iterator.next('我是第二个next');
iterator.next('我是第三个next');
iterator.next('我是第四个next');
产生可迭代对象

可以使用星号增强yield行为,让它能够迭代一个可迭代对象,从而一次产生一个值

//未增强yield
function * gen() {
            yield  [1, 2, 3];
}
 let genObj = gen();
 console.log(genObj.next());//[1, 2, 3]

//增强yield
function * gen() {
    yield * [1, 2, 3];
}
let genObj = gen();
for(const x of gen()) {
    console.log(x);
}// 1 2 3