es6特性-第一部分

let

let关键字主要用来进行变量的声明。有以下注意的点:

  • 变量名不能重复声明,防止变量被污染。var关键字可以

    let star ='罗志祥';
    let star ='小猪'; //执行后报错
    
  • let声明的变量只能在块级作用域(if、函数、for…)内有效。但不影响作用域链。

    {
        let girl = "周扬青';
    }
    console.log(girl); //报错
    
    {
    	let school ='尚硅谷';
    	function fn(){
    		console.log(school);
    	}
    	fn();//这块不会报任何错误
    }
    
  • 不存在变量提升。必须使用let先声明变量,然后在使用。

    console.log(song);
    let song ="恋爱达人'; //报错
    

以后声明变量都使用let关键字。

const

const使用这个关键字用来声明常量。有以下注意事项:

  • const声明的常量声明时必须赋值,否则报错。

  • const声明的常量的值不能修改。

  • 一般常量名使用大写(潜规则)

  • 块儿级作用域

  • 对于数组和对象的元素修改,不算做对常量的修改,不会报错。

    因为数组和对象的修改是对数组元素或者对象属性做修改,而数组和对象本身的地址不会发生变化。

//声明常量
const SCHOOL =‘尚硅谷';
const A; //报错:常量声明时必须赋值
const a = 100; //一般常量名大写
SCHOOL = 'ATGUIGU '; //报错:常量的值不能修改
{
 const PLAYER =UZI';
}
console.log(PLAYER); //报错:块儿级作用域

const TEAM = ['UZI','MXLG','Ming','Letme'];
TEAM.push('Meiko');//正常

变量的解构赋值

ES6允许按照一定模式从数组和对象中提取值,对变量进行赋值,这种的被称为解构赋值。

//数组解构赋值
const F4 = ['宋小宝', '小沈阳', '刘能', '赵四'];
let [song, xiao, liu, zhao] = F4; //注意:数组要对应的中括号
console.log(song);
console.log(xiao);
console.log(liu);
console.log(zhao);
//对象解构赋值
let wukong = {
    name: "悟空",
    age: 18,
    jineng: function () {
        console.log('72变');
    }
}
let { name, age, jineng } = wukong;  //注意:对象要对应的大括号
console.log(name);
console.log(age);
console.log(jineng);
jineng();

模板字符串

之前字符串的声明方式是单引号’'或者双引号""。ES6引入新的声明字符串的方式``(反引号)

//1.声明
let str =`我也是一个字符串哦!`;
console.log(str, typeof str);
//2.内容中可以直接出现换行符.单引号和双引号不允许。
let str = `
  • 沈腾
  • 玛丽
  • 魏翔
  • 艾伦
`
; //3.变量拼接 let lovest = '沈腾'; let out = `${lovest}是我心目中最搞笑的演员!`; //注意这里必须是$(变量名)这种格式。 console.log(out);

简化对象写法

ES6允许在大括号里面,直接写入变量和函数,作为对象的属性和方法。这样的书写更加简洁。

let name ="尚硅谷';
let change = function(){
	console.log('我们可以改变你!!");
}
//完整写法
const school = { 
	name:name,
	change:change,
    improve:function(){
		console.log("我们可以提高你的技能");
	}
}
//es6中简化写法                
const school = { 
	name,
	change,
    improve(){
		console.log("我们可以提高你的技能");
	}
}
//如果对象中的值对应的是字符串,而不是变量,那必须使用完整写法
const student = { 
	name:"light", //这里如果不加引号,就会找light变量
	age:18,
}

箭头函数

ES6 允许使用=>定义函数。省略function关键字。

//声明一个函数
let fn = () => {
    //...
}
let fn1 = (a, b) => {
    return a + b;
}
console.log(fn1(1, 2));
箭头函数注意事项
  • this是静态的,this始终指向函数声明时所在作用域下的 this的值。即使使用call方法调用。

    function getName(){
    	console.log(this.name);
    }
    let getName2 = ()=>{
    	console.1og(this.name);
    }
    window.name ='尚硅谷';
    const school = {
    	name:"ATGUIGU"
    }
    //直接调用
    getName(); //尚硅谷
    getName2();//尚硅谷
    //call方法调用
    getName.call(school); //ATGUIGU
    getName2.call(school);//尚硅谷 this对象始终指向window对象
    
  • 不能作为构造实例化对象,否则会报错

  • 不能使用arguments 变量,否则会报错

箭头函数简写
  • 当形参有且只有一个的时候,可以省略小括号。

    let add = n => {
    	return n + n;
    }
    console.log(add(9)); //18
    
  • 当代码体只有一条语句的时候,此时花括号和return必须省略而且语句的执行结果就是函数的返回值。

    let pow = n => n*n;
    console.log(pow(8));
    
总结

箭头函数适合与this 无关的回调。比如:定时器,数组的方法回调等。

箭头函数不适合与this有关的回调。比如:事件回调,对象的方法等。

函数参数的默认值

ES6允许给函数参数赋值初始值。

  • 形参初始值具有默认值的参数,一般位置要靠后(潜规则)。

  • 函数参数赋值初始值可以与解构赋值结合使用

    //函数参数解构赋值
    function connect({ host, username, passwd, other = 'no' }) {
        console.log(host, username, passwd, other); //baidu.com root 123456 no
    }
    connect({
        host: 'baidu.com',
        username: 'root',
        passwd: '123456'
    });
    

rest参数

ES6引入rest参数,用于获取函数的实参,用来代替arguments。

//ES5获取实参的方式
function date(){
	console.log(arguments); //打印出来是个对象
}
date('白芷','阿娇','思慧');
//rest参数
function date(...args){
	console.log(args); //打印出来是个数组
}
date('阿娇',"柏芝",'思慧");

rest参数是将参数以数组的方式存储,然后传入函数中。这样我们就可以通过数组api对rest参数进行处理。

注意:如果函数中有多个形参,rest参数必须放在最后,否则会报错。

function at(a, b, c, ...args) {
    console.log(a, b, c, args);
}
at(1, 2, 3, 4, 5, 6, 7, 8); //1 2 3 [4, 5, 6, 7, 8]

扩展运算符

...扩展运算符能将『数组』转换为逗号分隔的『参数序列

const tfboys = ['王俊凯', '易烊千玺', '王源'];
function chunwan() {
    console.log(arguments);
}
chunwan(tfboys); //对象
chunwan(...tfboys); //直接取数组
扩展运算符应用
  1. 数组的合并
const kuaizi = ['王太利', '肖央'];
const fhcq = ['玲花', '曾毅'];
//es5
var zuixuanxiaopingguo = kuaizi.concat(fhcq);
console.log(zuixuanxiaopingguo);// ['王太利', '肖央', '玲花', '曾毅']
//扩展运算符
//原理: 1.扩展运算符先把数组转化成逗号分隔的参数序列
//       ...kuaizi => '王太利', '肖央'  ...fhcq => '玲花', '曾毅' 
// 2.组合数组
// zuixuanxiaopingguo = [...kuaizi, ...fhcq] => ['王太利', '肖央', '玲花', '曾毅']
zuixuanxiaopingguo = [...kuaizi, ...fhcq];
console.log(zuixuanxiaopingguo);// ['王太利', '肖央', '玲花', '曾毅']
  1. 数组克隆
const sanzhihua = ['E', 'G', 'M'];
const sanyecao = [...sanzhihua];
console.log(zuixuanxiaopingguo);//['E', 'G', 'M']
  1. 将伪数组转为真正的数组
const divs = document.querySelectorAll('div');
console.log(divs); //对象
const divArr = [...divs];
console.log(divArr); //转化为数组

Symbol

ES6引入了一种新的原始数据类型 Symbol,表示独一无二的值。它是JavaScript语言的第七种数据类型,是一种类似于字符串的数据类型。Symbol的初衷:解决对象的属性名冲突

Symbol的创建
//创建Symbol
let s = Symbol();
console.log(s, typeof s); //Symbol() "symbol"
let s2 = Symbol("张三"); //这块构造函数里面的字符串只是对Symbol数据的描述
let s3 = Symbol("张三");
//symbol.for创建
let s4 = Symbol.for("张三");
let s5 = Symbol.for("张三');

Symbol值通过Symbol函数生成。这就是说,对象的属性名现在可以有两种类型,一种是原来就有的字符串,另一种就是新增的Symbol类型。凡是属性名属于Symbol类型,就都是独一无二的,可以保证不会与其他属性名产生冲突。

Symbol特点
  1. Symbol 的值是唯一的(es内部实现唯一性),用来解决命名冲突的问题。

  2. Symbol值不能与其他数据进行运算

  3. Symbol定义的对象属性不能使用for...in循环遍历,但是可以使Reflect.ownKeys来获取对象的所有键名

Symbol的使用场景

在企业开发中如果需要对一些第三方的插件、框架进行自定义的时候可能会因为添加了同名的属性或者方法, 将框架中原有的属性或者方法覆盖掉为了避免这种情况的发生, 框架的作者或者我们就可以使用Symbol作为属性或者方法的名称。

//第一种添加方法
let bird = {
    name: '麻雀',
    fly: function () {
        console.log('我要飞得很高!')
    },
    eat: function () {
        console.log('该吃饭了!')
    }

}
//给对象添加扩展的属性或者方法
let addMethod = {
    fly: Symbol(),
    eat: Symbol()
}
bird[addMethod.fly] = function () {
    console.log('请不要飞得太高');
}
bird[addMethod.eat] = function () {
    console.log('请不要吃的太饱');
}
//调用
bird.eat();
bird.fly();
bird[addMethod.eat]();
bird[addMethod.fly]();
//第二种添加方法
let youxi = {
    name: "狼人杀",
    [22]: function () {
        console.log('sfsdfsdaf');
    },
    [Symbol('say')]: function () { //相当于私有方法,不得被调用
        console.log("我可以发言");
    },
    [Symbol('zibao')]: function () { //相当于私有方法,不得被调用
        console.log("我可以自爆");
    }
}
console.log(youxi);
Symbol的内置值

除了定义自己使用的 Symbol值以外,ES6还提供了11个内置的Symbol值,指向语言内部使用的方法。

其实这些值都是使用Symbol的属性,而这些Symbol的属性可以作为对象的属性来使用。
es6特性-第一部分_第1张图片

class Person {
    static [Symbol.hasInstance](param) {
        console.log(param);
        console.log('我被调用了');
        return false;
    }
}
let swk = {
    name: '孙悟空',
}
console.log(swk instanceof Person);

迭代器

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

  1. ES6创造了一种新的遍历命令for...of循环,lterator接口(这里的lterator接口,其实是指对象里面的一个属性,例如:Symbol(Symbol.iterator),只要有这个属性,就可以使用for...of消费)主要供 for...of消费。
   const xiyou = ['孙悟空', '猪八戒', '唐僧', '沙僧'];
   for (const item of xiyou) {
       console.log(item);
   }
  1. 原生具备iterator接口的数据(可用for of遍历)

    Array、Arguments、Set、Map、String、TypedArray、NodeList。这些数据都具有Symbol(Symbol.iterator)属性

工作原理
  • 创建一个指针对象,指向当前数据结构的起始位置

    let iterator = xiyou[Symbol.iterator]();

  • 第一次调用对象的next方法,指针自动指向数据结构的第一个成员

    console.log(iterator.next()); //{value: '孙悟空', done: false}
    console.log(iterator.next()); //{value: '猪八戒', done: false}
    ...
    
  • 接下来不断调用next方法,指针一直往后移动,值到指向最后一个成员

    console.log(iterator.next()); //{value: '沙僧', done: false}
    
  • 每调用next 方法返回一个包含value和 done属性的对象

    {value: '沙僧', done: false}

迭代器主要用来自定义遍历对象

//自定义遍历对象
const ig = {
    name: 'ig',
    staff: ['theshy', 'ming', 'rookie', 'jacklove', 'ming'],
    [Symbol.iterator]() {
        let index = 0;
        let _this = this;
        return {
            next: function () {
                if (index < _this.staff.length) {
                    index++;
                    return { value: _this.staff[index], done: false };
                } else {
                    return { value: undefined, done: true }
                }
            }
        };
    }
};
for (let v of ig) {
    console.log(v);
}

生成器

生成器函数是ES6提供的一种异步编程解决方案,语法行为与传统函数完全不同。

我们之前的异步编程是纯回调函数:nodefs、 ajax、mongodb

生成器函数声明时,需要在function 和函数名之间需要加 * yield表示程序执行到这里会交出执行权,等待结果返回。它需要在协程Generator 函数中运行。

function * gen(){
    yield 'xxxx';
    //...
    yield 'xxxx';
}

当执行gen()的时候,并不执行 generator 函数体,而是返回一个迭代器。迭代器具有next()方法,每次调用 next() 方法,函数就执行到yield语句的地方。next() 方法返回一个对象,其中value属性表示 yield 关键词后面表达式的值,done 属性表示是否遍历结束。generator 生成器通过nextyield的配合实现流程控制。

function* gen() {
    console.log(111);
    yield '一只没有耳朵';
    console.log(222);
    yield '一只没有尾部';
    console.log(333);
    yield '真奇怪';
    console.log(444);
}
let iterator = gen();
console.log(iterator.next()); //111 {value: '一只没有耳朵', done: false}
console.log(iterator.next()); //222 {value: '一只没有耳朵', done: false}
console.log(iterator.next()); //333 {value: '一只没有耳朵', done: false}
console.log(iterator.next()); //444 {value: undefined, done: true}

for (const item of gen()) {
    console.log(item); //每次输出返回的{value: '一只没有耳朵', done: false}对象的value值并且执行yield之上的代码
}
生成器参数
function* gen1(arg) {
    console.log(arg);
    let one = yield 111;
    console.log(one);
    let two = yield 222;
    console.log(two);
    let three = yield 333;
    console.log(three);
}
//执行获取迭代器对象
let itor = gen1('AAA');
console.log(itor.next());//AAA {value: 111, done: false}
// next方法可以传入实参
console.log(itor.next("BBB"));//BBB {value: 222, done: false}
console.log(itor.next("CCC"));//CCC {value: 333, done: false}
console.log(itor.next("DDD"));//DDD {value: undefined, done: true}

第一次执行next函数时,可以根据生成器函数的参数接受数据。以后每次执行next所传递的参数,在函数体中都由yield语句执行。例如第二次next传递的参数由函数体中第一个yield语句执行完毕后返回,第三次次next传递的参数由函数体中第二个yield语句执行完毕后返回,…

生成器实例

要求:1s后控制台输出111, 2s后输出222,3s后输出333

我们一般的做法:

setTimeout(() => {
    console.log('111');
    setTimeout(() => {
        console.log('222');
        setTimeout(() => {
            console.log('333');
        }, 3000);
    }, 2000);
}, 1000);

上面的编写方式如果需要多个回调,显然这种写法肥肠臃肿,这种无尽的回调方式称之为回调地狱。

可以通过生成器函数方式规避这种写法:

function one() {
    setTimeout(() => {
        console.log('111');
        iterator.next();
    }, 1000)
}
function two() {
    setTimeout(() => {
        console.log('222');
        iterator.next();
    }, 2000)
}
function three() {
    setTimeout(() => {
        console.log('333');
        iterator.next();
    }, 3000)
}
function* gen() {
    yield one();
    yield two();
    yield three();
}
let iterator = gen();
iterator.next();

要求:先获取用户数据,在获取用户订单数据,然后获取商品数据。

function getUserData() {
    setTimeout(() => {
        let data = "用户数据";
        itor.next(data);
    }, 1000);
}
function getOrderData() {
    setTimeout(() => {
        let data = "订单数据";
        itor.next(data);
    }, 1000);
}
function getGoodsData() {
    setTimeout(() => {
        let data = "商品数据";
        itor.next(data);
    }, 1000);
}
function* gen1() {
    let user = yield getUserData();
    console.log(user);
    let order = yield getOrderData();
    console.log(order);
    let goods = yield getGoodsData();
    console.log(goods);
}
let itor = gen1();
itor.next();

你可能感兴趣的:(ecmascript,es6,前端,ecmascript)