ES6基本使用

初识ES6

ES6,全称 ECMAScript 6.0 ,是 JavaScript 的下一个版本标准,2015.06 发版。
  • ES6 主要是为了解决 ES5 的先天不足,比如 JavaScript 里并没有类的概念,但是目前浏览器的 JavaScript 是 ES5 版本,大多数高版本的浏览器也支持 ES6,不过只实现了 ES6 的部分特性和功能。
ECMAScript 的背景
  • JavaScript 是大家所了解的语言名称,但是这个语言名称是商标( Oracle 公司注册的商标)。因此,JavaScript 的正式名称是 ECMAScript 。1996年11月,JavaScript 的创造者网景公司将 JS 提交给国际化标准组织 ECMA(European computer manufactures association,欧洲计算机制造联合会),希望这种语言能够成为国际标准,随后 ECMA 发布了规定浏览器脚本语言的标准,即 ECMAScript。这也有利于这门语言的开放和中立。

开始学习ES6新语法

变量的定义(let和const)
  • let的作用是声明一个变量,与var类似 let str = 'oh,yes'

  • let特点: 在块作用域下有效,不能重复声明,不会预处理,不存在变量提升

  • 什么时候使用?

    • 循环遍历加监听
    • 使用let代替var是一种流行趋势

  • 小demo(进行遍历监听事件的时候,会存在值覆盖的问题,可以使用闭包来解决,但是这种方式比较麻烦,再加入let关键字后,我们可以使用let来代替var声明变量,则会有块作用域效果)

		for(var i=0;i<btns.length;i++){
	        var btn = btns[i];
	        (function(i){
	            btn.onclick = function(){
	                alert(i)
	            }
	        })(i)
	        }
  • const的作用是定义一个常量
    • 在ES6之前,并没有真正意义上的常量,只是在定义变量的时候,给变量名为全大写作为常量的标明,但是在浏览器解析是它任然只是一个变量。
    • 语法 const USER = 'root',特点:一旦定义不能修改 ,其他同let一样。一般用于不会修改的数据
解构赋值
  • 从对象或者数组中提取数据,并赋值给一个或多个变量(相比传统取值方式,更加便捷并且解析速度会更快),也可用与参数的传递

  • 基本语法:

    • 数组:let [a,b] = [1,2]
    • 对象:let {name,age} = {name:'jack',age:18}

  • 对象解构时,需要在接收的时候也是一个对象,接收的对象中写入需要接收的属性,属性名需要在解构的对象中存在

  • 数组解构时,需要在接收的时候也是一个数组,接收的数组中的变量位置,对应数组下标取值(可以使用逗号占位的形式取下标)

模板字符串
  • 简化字符串的操作
  • 模板字符串必须使用`` 反引号括起来
  • 使用变量的部分用 ${变量名}定义
		let love = '爱情'
		let food = '面包'
		let str = `${love}和${food}都会有的 `
对象的简化写法
  • 省略同名的属性值
  • 省略方法的function关键字
  • 小demo(在对象方法或者设置属性值时,调用对象中的属性需要使用this关键字)
		let name = 'dson'
		let age = 18
		
		let obj = {
			name,
			age,
			set(name){
				this.name = name
			}
		}
		
		obj.set('jack')
		console.log(obj.name)
剩余运算符
  1. rest可变参数 (可以用来代替argument对象)

    • 比arguments对象更加灵活,可以接受剩余参数,但是只能是最后部分参数
    • 只在第一次使用的时候加上… ,下次使用时直接用后面的变量名即可
    • 获取得到的是一个纯粹的数组,可以使用forEach方式遍历
      	function demo(a,b,...gather){
          console.log(arguments)
          arguments.forEach(function(item,index){
              console.log(item,index)
          })
      
          console.log(gather)
          
          gather.forEach(function(item,index){
              console.log(item,index)
          })
          }
          
          demo(1,2,3,4)
      
  2. 扩展运算符 (可以用于操作数组,不能用于对象)

    	let arr = [2,3,4]
        let arr2 = [1,5]
        arr2 = [1,...arr,5]
        console.log(arr.concat(arr2))
    
        let obj2 = {
            name:'jack',
            age:18
        }
        
        console.log(...obj2)
    
形参的默认值
  • 在ES5中形参的默认值为undefined,ES6以后可以给形参手动设置默认值
  • 当没有参数传入的时候,默认使用手动设置的值
		function demo(num1 = 0, num2 = 0){
			this.num1 = num1
			this.num2 = num2
		}
		let dm = new demo(2,3)
		console.log(dm)
箭头函数的使用 [ 搭配demo食用效果更佳 ]
  1. 箭头函数是用来定义匿名函数的,基本语法 demo = () => console.log('内容')

  2. 箭头函数可以传递参数 demo = str => str 等于 function demo(str){return str}

    • 参数部分

      • 不传参数时,必须使用()进行占位
      • 传递一个参数的时()可加,可不加
      • 传递多个参数的时候需要使用()将参数包裹
    • 函数体部分

      • 函数体不使用{}时,默认返回结果
      • 函数体中如果存在多个语句,则需要使用{}包裹,需要返回值时,可以手动添加返回值

  3. 箭头函数多用于定义回调函数

  4. 箭头函数的特性

    • 语法简洁
    • 箭头函数没有自己this,箭头函数的this是定义的时候处在的对象,而不是调用时候的对象
    • 可以理解为:
      • 箭头函数的this是看外层是否存在函数
      • 如果有,外层函数的this就是箭头函数的this
      • 如果没有,this则是指向window
Promise对象
  1. 什么是Promise对象

    • Promise对象指代未来某个时间节点将要发生的事件 [ 通常为一个异步操作 ]
    • 该对象可以将异步操作以同步的流程表达出来,避免多层嵌套回调函数
    • 该对象是一个构造函数,用来生成promise实列

  2. Promise 异步操作有三种状态:pending(进行中 [ 初始化 ])、fulfilled(已成功)和 rejected(已失败)

    • fulfilled和rejected状态只会有其中一个生效

  3. Promise对象基本使用

    • 创建promise对象

        let promise = new Promise((resolve,reject)=>{
        	//进行异步操作,一般为ajax数据请求
        	//resolve(res)
        	reject(res)
        })
      
        promise.then((res)=>{
            console.log('成功')
        },(res)=>{
            console.log('失败')
        }) 
      
    • 调用成功的resolve(),或者失败的reject()方法最终都会返回一个promise对象。使用then方法可以对不同状态进行操作。

    • then的第一个回调函数对应的是resolve()方法,第二个回调函数对应reject()方法

    • then的回调函数中可以接收对应方法传递的参数

  4. 在保证返回值为promise对象时,可以进行链式操作then()方法[ 具体请看demo ]

Symbol类型的使用
  1. ES6 数据类型除了 Number 、 String 、 Boolean 、 Object、 null 和 undefined ,还新增了 Symbol

  2. Symbol类型的特性:

    • Symbol属性对应的值是唯一的,解决命名冲突问题
    • Symbol的值不能与其他数据类型进行计算,字符串拼接也不行
    • Symbol不能使用 for in 和 for of 遍历
  3. 基本使用:let symbol = Symbol()

  4. 由于每一个 Symbol 值都是不相等的,这意味着 Symbol 值可以作为标识符,用于对象的属性名,就能保证不会出现同名的属性。这对于一个对象由多个模块构成的情况非常有用,能防止某一个键被不小心改写或覆盖。

	let mySymbol = Symbol();

    // 第一种写法
    let a = {};
    a[mySymbol] = 'Hello!';

    // 第二种写法
    let a = {
      [mySymbol]: 'Hello!'
    };

    // 第三种写法
    let a = {};
    Object.defineProperty(a, mySymbol, { value: 'Hello!' });

    // 以上写法都得到同样结果
    a[mySymbol] // "Hello!"
  1. Symbol的内置值

    • ES6中为Symbol提供了11个内置的值,指向语言内部使用的方法
    • Symbol.iterator属性,通常用于定义对象的唯一属性
			let obj = {
		        name:'jack',
		        age:18
		    }
		    obj[Symbol.iterator] = function(){
		
		    }
Iterator(遍历器)
  1. 概念:遍历器(Iterator)就是这样一种机制。它是一种接口,为各种不同的数据结构提供统一的访问机制。

  2. iterator主要作用

    • 为各种数据结构,提供一个统一的、简便的访问接口

    • 使得数据结构的成员能够按某种次序排列

    • ES6 创造了一种新的遍历命令for…of循环,Iterator 接口主要供for…of消费

  3. Iterator 的遍历过程是这样的。

    1. 创建一个指针对象,指向当前数据结构的起始位置。也就是说,遍历器对象本质上,就是一个指针对象。

    2. 第一次调用指针对象的next方法,可以将指针指向数据结构的第一个成员。

    3. 第二次调用指针对象的next方法,指针就指向数据结构的第二个成员。

    4. 不断调用指针对象的next方法,直到它指向数据结构的结束位置。

    5. 遍历结束时,value的值为undefined,done的值为true,是否执行的依据为done的值为false时。

    • 每一次调用next方法,都会返回数据结构的当前成员的信息。具体来说,就是返回一个包含value和done两个属性的对象。其中,value属性是当前成员的值,done属性是一个布尔值,表示遍历是否结束。
  4. 原生具备iterator接口数据(可使用for of 遍历)

    • Array
    • Map
    • Set
    • String
    • TypedArray
    • 函数的 arguments 对象
    • NodeList (DOM)对象
  5. for of方法的使用

    • for of 不能遍历普通对象

    • 使用的iterator接口

    • 剩余运算符使用的也是 iterator接口

        for(let key of arr){
            console.log(key)
        }
      
Symbol.iterator基本实现原理
	function iterator(arr) {
    // 相当于内置的指针对象
    let index = 0
    return {
        next() {
            // 判断使用三元运算符判断当前指针下标是否超过数组的长度
            return index < arr.length ? 
            { value: arr[index++], done: false } : 
            { value: arr[index++], done: true };
        	}
        }
    }
    let arr = [5, 4, 3, 2, 1]
    //调用一次这个方法,就取出对应下标的值
    let iter = iterator(arr)
	console.log(iter.next())
Symbol.iterator底层实现原理
数组遍历实现
  1. 手动修改Array原型中的Symbol.iterator 指向到自定义函数中
 Array.prototype[Symbol.iterator] = iteratorTool
  1. 修改原型对象方法后,自定义的iteratorTool()方法,不在接收参数,此时函数中的数组长度调用会发生错误。
  2. 在iteratorTool()方法中,this指向的是遍历的数组,是因为当调用for…of方法时,会触发arr数组中的Symbol.iterator属性中的方法。
    • 首先将this保存,防止作用域污染let _this = this
    • 其次修改函数中的arr.length_this.length即可
对象遍历和数组遍历共同实现
  1. 函数需要同时实现两种遍历形式,需要进行判断,当前this是数组还是对象,

    • 使用 instanceof 关键字用于判断_this instanceof Array
  2. 在对象中不存在下标概念,所以使用取下标的形式,不能将对象中的属性值拿出来

    • 将需要遍历的对象转换成数组形式Object.keys(obj)
    • 数组形式下我们可以拿到所有属性的length长度Object.keys(obj).length,用于判断next()函数是否继续执行
    • 将返回的对象中的value属性的值修改为对象取值形式_this[Object.keys(obj)[index++]]
Generator 函数(过渡异步处理-不常用)
  1. Generator 函数的概念

    • Generator 函数是 ES6 提供的一种异步编程解决方案,语法行为与传统函数完全不同
    • Generator 函数内部封装不同状态的数据
    • 用来生成遍历器对象
    • 可暂停函数(惰性求值),yield关键字进行暂停,next()方法启动。每次返回的是yield后的表达式执行的结果
  2. Generator 函数的特性

    • function与函数名之间有一个星号* function* demo(){}
    • 内部使用yield来定义不同状态,基本定义
function* demo(){
    let result = yield 1;
    yield 2;
}



	- 调用 Generator 函数后,该函数并不执行,返回的也不是函数运行结果,而是一个指向内部状态的指针对象
	- 调用next()方法函数内部的逻辑开始执行[ 至少调用一次,函数体才会执行 ],遇到yield或return语句时停止。yield后面的那个表达式的值,作为返回的对象的value属性值
	-  在次调用next()方法会从上一次的yield出开始执行,直到最后
	-  yield在未设定返回值是默认为undefined


3. Generator 函数的基本使用
	- next()方法需要在得到调用函数的返回对象下使用
	```
			function* generatorTool(){
		        console.log('我要开始啦~')
		        yield 1
		        console.log('我在中间')
		        yield 2
		        console.log('我已经结束了~')
		    }
		    let Gt = generatorTool()
		    Gt.next()
	```
  1. Generator 函数处理异步操作
    • 在yield关键字后可以调用函数(进行数据请求等)

    • 在调用的函数中使用next()方法,将对象指针下移,逻辑代码继续执行。

    • 调用next()方法时可以进行传参,参数作为yield关键字后的表达式返回值

        function AsyncTool(){
            setTimeout(()=>{
                let data = '我是数据'
                Gt.next(data)
            },2000)
        }
        	
        function* generatorTool(){
            let res = yield AsyncTool()
            yield AsyncTool(res)
        
        }
      

####async 函数的使用

  1. 概念:真正意义上解决了异步回调的问题,同步流程表达异步操作

  2. 本质:Generator的语法糖

  3. async 函数的基本语法:

     async function demo(){
         await 异步操作;
         await 异步操作;
     }
    

4.async 函数的特性:
- 不需要像Generator去调用next()方法,遇到await关键字时等待,当前的异步操作完成后继续往下执行
- 返回的是一个Promise对象,可以使用then()方法进行操作
- async关键字取代了Generator函数的*号,await取代了yield
- 相对其他异步操作解决方案更简洁

5.async搭配Promise进行异步操作
- await关键字会自动识别Promise对象的state状态值,用于判断是否继续执行

	function promiseTool(){
        return new Promise((resolve,reject)=>{
            setTimeout(()=>{
                console.log('我执行了')
                resolve(res)
            },2000)
        })
    }

    async function asyncTool(){
        console.log('我开始了~')
        let res = await promiseTool()
        console.log('我继续')
        await promiseTool(res)
        console.log('我完事了')

    }
    asyncTool()






Class关键字

Class的基本使用
  1. 通过class定义类

     class Person{}		
    
  2. 在类中通过constructor() 定义构造方法

     class Person{
     	constructor(name,age){
             console.log('构造函数会被自动调用');
             this.name = name
             this.age = age
     	}
     }
    
  3. 通过new来创建类的实列

     let person = new Person('jack',18)
    
  4. 类的一般方法 [ 在类中直接定义的方法可以用于继承 ]

    • 等同于在原型对象中直接添加方法Person2.prototype.say = function(){}

        say(){
            console.log(this.name,this.age);
        }
      

5.static关键字定义静态方法或者属性
- static静态关键字声明的方法或属性只提供给类的对象使用,实例不能使用

	static demo(){
        console.log('我是静态方法')
    }
类的继承
  1. 通过extends实现类的继承

    • 继承了父类的所有属性和方法

    • 等同于ChildPerson.prototype = new Person()

        class ChildPerson extends Person{}	
      
  2. 通过super()调用父类的构造方法

    • 子类自己的this对象,必须先通过父类的构造函数完成塑造,得到与父类同样的实例属性和方法,然后再对其进行加工,加上子类自己的实例属性和方法。如果不调用super方法,子类就得不到this对象

        class ChildPerson extends Person{
            constructor(name,age,sex){
                super()
                this.sex  = sex
            }
        }
        let Cp = new ChildPerson('tom',23,'1')
        Cp.say()
      
    • 如果需要使用父类中的的构造函数的属性,需要对super进行传参super(name,age)

  3. 重写继承父类中的一般方法

    • 默认继承的方法在隐式原型中,运行时会一层一层往下找

    • 当父类的方法不能满足子类实例对象的需求时进行重写 [ 当子类中有和父类中重名方法时,使用子类中的方法,不再继续往下 ]

        say(){
            console.log(this.name,this.age,this.sex)
        }
      

其他新增扩展

字符串的新增方法
  1. includes(str) 判断是否包含指定的字符串
  2. startsWith(str) 判断是否以指定的字符开头
  3. endsWith(str) 判断是否以指定的字符结尾
  4. repeat(number) 将字符串重复指定次数
数值的扩展
  1. Number.isFinite() 判断是否为一个有限大的数
  2. Number.isNaN() 判断是否是NaN
  3. Number.isInteger() 判断一个数值是否为整数
  4. Number.parseInt() 转换字符串为数值
  5. Math.trunc(number.float) 去除小数部分
数组的扩展
  1. Array.from() 将伪数组对象或者可遍历对象转换成纯粹的数组

    • 此处获取到一组button按钮的对象是一个伪数组

        let btns = document.getElementsByTagName('button')
        Array.from(btns).forEach((item,index)=>{
            console.log(item)
        })
      
  2. Array.of() 用于将一组值,转换为数组

     Array.of(1,'str',true)	
    
  3. find() 找出第一个满足条件的元素,返回该成员 ,没有则返回undefined

    • 这是实例对象中的方法,完整写法 Array.prototype.find()

      find(function(value,index,arr){return 要找的元素})

    • 基本使用

      let arr = [1,2,4,2,4,6]
      let res = arr.find(function(item,index){
      return item > 3
      }

  4. findIndex() 找出第一个满足条件的元素,返回该元素在数组中的下标 ,没有则返回-1

     findIndex(function(value,index,arr){return 要找的元素})	
    
对象的扩展
  1. Object.is(value1,value2) 比较两个值是否相等

  2. Object.assign(target,sourcel) 用于对象的合并,将源数组的属性赋值到目标属性上

     let obj1 = {name:'jack',age:18}
     let obj2 = {}
     Object.assign(obj2,obj1)
     console.log(obj2)		
    
  3. 直接操作__porto__ 属性

set和map数据结构

set的使用

ES6 提供了新的数据结构 Set。它类似于数组,但是成员的值都是唯一的,没有重复的值。

const s = new Set();

[2, 3, 5, 4, 5, 2, 2].forEach(x => s.add(x));	// add()是set对象添加元素的方法

for (let i of s) {
  console.log(i);
}

利用这个特性可以简单的完成一些数组中相同值的排除

向 Set 加入值的时候,不会发生类型转换,所以5和"5"是两个不同的值。Set 内部判断两个值是否不同,使用的算法叫做“Same-value-zero equality”,它类似于精确相等运算符(===),主要的区别是向 Set 加入值时认为NaN等于自身,而精确相等运算符认为NaN不等于自身。另外,两个对象总是不相等的。

Set函数可以接受一个数组(或者具有 iterable 接口的其他数据结构)作为参数,用来初始化。

// 例一
const set = new Set([1, 2, 3, 4, 4]);
[...set]
// [1, 2, 3, 4]

// 例二
const items = new Set([1, 2, 3, 4, 5, 5, 5, 5]);
items.size // 5

// 例三
const set = new Set(document.querySelectorAll('div'));
set.size // 56

// 类似于
const set = new Set();
document
 .querySelectorAll('div')
 .forEach(div => set.add(div));
set.size // 56

Set 实例的属性和方法

Set 结构的实例有以下属性。
  • Set.prototype.constructor:构造函数,默认就是Set函数。
  • Set.prototype.size:返回Set实例的成员总数。
Set 实例的方法分为两大类:操作方法(用于操作数据)和遍历方法(用于遍历成员)。下面先介绍四个操作方法。
  • Set.prototype.add(value):添加某个值,返回 Set 结构本身。
  • Set.prototype.delete(value):删除某个值,返回一个布尔值,表示删除是否成功。
  • Set.prototype.has(value):返回一个布尔值,表示该值是否为Set的成员。
  • Set.prototype.clear():清除所有成员,没有返回值。
s.add(1).add(2).add(2);
// 注意2被加入了两次

s.size // 2

s.has(1) // true
s.has(2) // true
s.has(3) // false

s.delete(2);
s.has(2) // false

Array.from方法可以将 Set 结构转为数组。

const items = new Set([1, 2, 3, 4, 5]);
const array = Array.from(items);
遍历操作

Set 结构的实例有四个遍历方法,可以用于遍历成员。

  • Set.prototype.keys():返回键名的遍历器
  • Set.prototype.values():返回键值的遍历器
  • Set.prototype.entries():返回键值对的遍历器
  • Set.prototype.forEach():使用回调函数遍历每个成员
let set = new Set(['red', 'green', 'blue']);

for (let item of set.keys()) {
  console.log(item);
}
// red
// green
// blue

for (let item of set.values()) {
  console.log(item);
}
// red
// green
// blue

for (let item of set.entries()) {
  console.log(item);
}
// ["red", "red"]
// ["green", "green"]
// ["blue", "blue"]

WeakSet

WeakSet 结构与 Set 类似,也是不重复的值的集合。但是,它与 Set 有两个区别。
首先,WeakSet 的成员只能是对象,而不能是其他类型的值。

const ws = new WeakSet();
ws.add(1)
// TypeError: Invalid value used in weak set
ws.add(Symbol())
// TypeError: invalid value used in weak set

第二个区别是WeakSeet中的对象都弱引用

Map

JavaScript 的对象(Object),本质上是键值对的集合(Hash 结构),但是传统上只能用字符串当作键。这给它的使用带来了很大的限制。

为了解决这个问题,ES6 提供了 Map 数据结构。它类似于对象,也是键值对的集合,但是“键”的范围不限于字符串,各种类型的值(包括对象)都可以当作键。也就是说,Object 结构提供了“字符串—值”的对应,Map 结构提供了“值—值”的对应,是一种更完善的 Hash 结构实现。如果你需要“键值对”的数据结构,Map 比 Object 更合适。

下面代码使用 Map 结构的set方法,将对象o当作m的一个键,然后又使用get方法读取这个键,接着使用delete方法删除了这个键。

const m = new Map();
const o = {p: 'Hello World'};

m.set(o, 'content')
m.get(o) // "content"

m.has(o) // true
m.delete(o) // true
m.has(o) // false

作为构造函数,Map 也可以接受一个数组作为参数。该数组的成员是一个个表示键值对的数组。

const map = new Map([
  ['name', '张三'],
  ['title', 'Author']
]);

map.size // 2
map.has('name') // true
map.get('name') // "张三"
map.has('title') // true
map.get('title') // "Author"
实例的属性和操作方法

Map 结构的实例有以下属性和操作方法。

  1. size属性返回 Map 结构的成员总数。

  2. Map.prototype.set(key, value)
    set方法设置键名key对应的键值为value,然后返回整个 Map 结构。如果key已经有值,则键值会被更新,否则就新生成该键。

    const m = new Map();
    
    m.set('edition', 6)        // 键是字符串
    m.set(262, 'standard')     // 键是数值
    m.set(undefined, 'nah')    // 键是 undefined
    
  3. Map.prototype.get(key)
    get方法读取key对应的键值,如果找不到key,返回undefined。

  4. Map.prototype.has(key)
    has方法返回一个布尔值,表示某个键是否在当前 Map 对象之中。

  5. Map.prototype.delete(key)
    delete方法删除某个键,返回true。如果删除失败,返回false。

  6. Map.prototype.clear()
    clear方法清除所有成员,没有返回值。

遍历方法

Map 结构原生提供三个遍历器生成函数和一个遍历方法。

  • Map.prototype.keys():返回键名的遍历器。
  • Map.prototype.values():返回键值的遍历器。
  • Map.prototype.entries():返回所有成员的遍历器。
  • Map.prototype.forEach():遍历 Map 的所有成员。
const map = new Map([
  ['F', 'no'],
  ['T',  'yes'],
]);

for (let key of map.keys()) {
  console.log(key);
}
// "F"
// "T"

for (let value of map.values()) {
  console.log(value);
}
// "no"
// "yes"

for (let item of map.entries()) {
  console.log(item[0], item[1]);
}
// "F" "no"
// "T" "yes"

// 或者
for (let [key, value] of map.entries()) {
  console.log(key, value);
}
// "F" "no"
// "T" "yes"

// 等同于使用map.entries()
for (let [key, value] of map) {
  console.log(key, value);
}
// "F" "no"
// "T" "yes"
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值