js--es6学习
1.1 es6块级作用域 let
let 与 var 区别
- var
<ul>
<li>000001</li>
<li>000002</li>
<li>000003</li>
</ul>
<script>
var oli = document.querySelectorAll('ul li')
for(var i = 0; i<oli.length;i++){
oli[i].onclick = function(){
console.log(i);
}
}
</script>
完成不了当点击li时,点击谁就显示谁的下标牵引值,他就会一点击就显示一个3;
原因是因为用var会使得 for循环一下就执行完了,而点击事件是异步的操作,此时for循环已完成,现在i为全局变量使得无论点哪一个都为3
改进方案
- 添加第三方变量法
<ul>
<li>000001</li>
<li>000002</li>
<li>000003</li>
</ul>
<script>
var oli = document.querySelectorAll('ul li')
for(let i = 0; i<oli.length;i++){
oli[i].index = i
oli[i].onclick = function(){
console.log(this.index);
}
}
</script>
- let法
var oli = document.querySelectorAll('ul li')
for(let i = 0; i<oli.length;i++){
oli[i].onclick = function(){
console.log(i);
}
}
let 不可重复性
不能重复进行定义
let 没有变量提升了
不会报错
console.log(a);
var a = 0;
会报错
console.log(a);
let a= 0
原因是因为var 会使声明提前提取放到最前面,所以不会报错,但是let不行
即暂存区死亡:该变量存在,但是不能获取
1.2 const 声明常量
- 必须得赋值
- 赋值后,不能改变
- 声明不提升
- 不与顶层对象挂钩
const声明的变量一定不能改变吗?
一部分可以改变
即:
const mobj = {
name:'aasd'
age:98
}
const.name = 'asidn'
因为mobj属于复杂类型,mobj指向的是对象的地址,可以通过这个地址改变里面的值,没有改变地址,所以const声明的一部分变量可以被改变
但是可以通过freeze 来防止const里面的变量发生改变
const mobj =freeze( {
name: 'aasd',
age: 98,
})
mobj.name = 'asidn'
es6 – 变量结构赋值
- 给其数组赋值与交换
let arr = [2,[3,4],3,5,4,6]
let [a,[,s],,c] = arr;
//a就代表的2 c就代表的4 s就代表的4
//交换两个数,不用第三变量
let x=1, y=2;
[x,y] = [y,x]
console.log(x,y);
- 对象赋值
let obj = {
name:"shabi",
age: 100
}
let(age,name) = obj //这样就可以把name与age全部给拿出来了
let(name,age) = obj //这样也可以
//如果全局变量里面有一个叫age的,那么我们可以利用
let(name,age:co) = obj
1.3 模板字符串
主要运用 `` 的方式来进行添加到里面利用${}添加变量
var oul = document.querySelector('ul')
let arr = ['dsa','sad','sadav']
let oli = arr.map(function(item){
return `<li>${item}</li>`
})
oul.innerHTML = oli.join('')
1.4 字符串扩展
- includes 表示函数里面是否包含什么元素
let name = 'asdasdsa'
console.log(name.includes('asd'))//表示name里面是否包含asd连续的字符串,连续就返回true 错误就返回false
- starswith 表示前面开始查找元素 ,第二个值表示其下标索引值开始查找的地方
let name = 'asdasdsa'
console.log(name.starsWith('asd'))
- endswith 表示从后面开始查找元素,第二个值表示从后面开始的所有制查找
let name = 'asdasdsa'
console.log(name.endsWith('asd'))
- repeat 表示重复几次,自己写一次也算复制一次
let name = 'asdasdsa'
console.log(name.repeat(4))
//表示复制四次
- isNaN 与 isFinite
let numl = Number.isFinite(100) //true1t
let num2 = Number.isFinite(100/0) //falselet
let num3 = Number.isFinite(Infinity) // false
判断是否为NaN 和数字
它们与传统的全局方法isFinite(和isNaN的区别在于,传统方法先调用Number(将非数值的值转为数值,再进行判断,而这两个新方法只对数值有效,NumberisFinite对于非数值一律返回false,Number.isNaN0只有对于NaN才返回true,非NaN一律返回false。
1.5 数组扩展
…展开运算符
let arr [1,2,3]
// let arr2 = arr.concat()
Let arr2 = [ ...arr]
arr2.pop()
console.log (arr,arr25
合并数组
let arr = [1,2,3]
let arr2 =[4,5,6]
console.log([ ...arr, ...arr2])
收集剩余数组
Let myarr = [1,2,3,4,5,6,7,8]
let [a,b,...c] = myarr
console.log(a,b,c)
1.7 Symbol
// obj.getName()
Let s1 = Symbol()//生成了一个symbol类型数据
let s2 = Symbol()
//console.log(typeof s1)
console.log(s1===s2)//不相等
//1.不能进行运算
console.log(s1>"aaaaa")
//2.显示调用toString()
console.log(s1.toString()+"aaaa")
//3.隐式转换boolean
1.8 函数扩展
- 默认参数
function ajax(url,sda=231,awd=32e){
console.log(url,sda,awd)
}
ajax("aojd")
- 剩余参数
function text(a,bv,...data){
console.log(data);
}
text(1,2,3,5,8,5,6)
- 箭头函数:写法简单
let text()=>'12345646'
let arr = ['asd','asd','asdas']
let arr2 = arr.map((item)=>`<li>${item}</li>`)
document.write(arr2.join(''))
- 只有return时可以省略
- 省略要注意对象
let test = ()=>({name:"ashud,age:987})
- 如果只有一个参数可以省略()
let arr2 = arr.map(item=>`<li>${item}</li>`)
- 无法访问 agguments
- this指向父作用域
模糊查询mysearch.oninput = function(){ setTimeout(()=>{ console.log(this.value); },1000) }
2.1 Symbol
作用:防止变量重复导致变量重叠
属性:let set = Symbol()
注意:
- 不能进行计算
let ser = Symbol();
console.log(ser+"asd")//这样会报错
应该这样写:
let name = Symbol()
let age = Symbol()
let obj ={
[name]:"bad",
[age]:32
}
console.log(obj[name]);
- 可以作为常量
与const的区别就是 symbol()可以放在代码的不同执行,确定唯一的代码执行
const sp =Symbol();
const tupian =Symbol();
const music =Symbol();
function play(type){
switch(type){
case sp :
console.log("sad");
break;
case tupian:
console.log("ads");
break;
case music:
console.log("sadsa");
break
}
}
play(tupian)
3.1 Iterator迭代器
lterator 的作用有三个:
一是为各种数据结构,提供一个统一的、简便的访问接口;
二是使得数据结构的成员能够按某种次序排列;
三是ES6,创造了一种新的遍历命令for…of循环,lterator 接口主要供for…of循环
Iterator 的遍历过程是这样的。
(1)创建一个指针对象,指向当前数据结构的起始位置。也就是说,遍历器对象本质上,就是一个指针对象。
(2) 第一次调用指针对象的next方法,可以将指针指向数据结构的第一个成员。
(3)第二次调用指针对象的next方法,指针就指向数据结构的第二个成员。
(4)不断调用指针对象的next方法,直到它指向数据结构的结束位置。
let i = arr[symbol.iterator()
console.1og(i.next())
console.1og(i.next())
console.1og(i.next())
console.1og(i.next())
ES6 规定,默认的 terator 接口部署在数据结构的Symbol.iterator属性,或者说,一个数据结构只要具有Symbol.iterator属性,就可以认为是“可遍历的”(iterable) 。Symbol.iterator属性本身是一个函数,就是当前数据结构默认的遍历器生成函数。执行这个函数,就会返回一个遍历器。
3.2 set结构
他类似与数组,但是里面的元素不重复
方法:
let ser = new Set([])
let arr1 = [1,2,6,9,1,4,5,2]
let ser = new Set(arr1)
let arr2 = [...ser]
console.log(ser);
3.2.1 Set属性和方法
- 求其set长度
元素.size
let ser = new Set([1,2,3,5])
console.log(ser.size)
- 添加元素add
let ser = new Set()
ser.add(1);
ser.add(2)
- has表示检查里面是否含有该元素
let ser = new Set([1,2,5,9,5,7])
console.log(ser.has(8))//这里会显示出false,因为里面没有包含8
- delete删除
- clear 全部清除
3.2.2 遍历
set.prototype.keys): 返回键名的遍历器set.prototype.values(): 返回键值的遍历器Set.prototype.entries(): 返回键值对的遍历器set.prototype.forEach(): 遍历每个成员
let ser = new Set([1,2,5,9,5,7])
for(let i of ser){
console.log(i)
}
for(let i of ser.value){
console.log(i)
}
for(let i of ser.key){
console.log(i)
}
//这几个打印的值都为Set里面的元素
加强版数组去重:
let arr = [1,5,3,4,4,4,{name:"asd"},{name:"asd"},{age:"78"},"asd",'asd','asassa']
//封装一个函数,进行去重操作
function finds(arr){
//创建一个Set
let ser =new Set();
//通过has来去除,filter过滤
return arr.filter((item)=>{
let id = JSON.stringify(item)
if(ser.has(id)){
return false
}else{
ser.add(id)
return true;
}
})
}
console.log(finds(arr));
3.3 Map结构
类似于对象,也是键值对的集合,但是“键”的范围不限开字符串,各种类型的值(包括对象)都可以当作键.
console.log(m2.get(o))
console.log(m2.has( "age"))
m2.delete( "age")
console.log(m2.has( "age"))
4.1 Proxy代理
Proxy如其名,它的作用是在对象和和对象的属性值之间设置一个代理,获取该对象的值或者设置该对象的值,以及实例化等等多种操作,都会被拦截住,经过这一层我们可以统一处理,我们可以认为它就是“代理器
let obj ={}
let proxy = new Proxy(obj,{
get(target , key){
console.log('get',target[key]);
return target[key]//这里必须的有返回值才能获取到target[key]
},
set(target,key,value){
//target表示obj对象,key表示属性,value表示元素
if(key==='data'){
box.innerHTML = value//当data属性改变时,页面也会随着发生改变
}
console.log('set',target,key,value);
target[key] = value //这一步表示将属性带入
}
})
4.2 Reflect对象
Reflect 可以用于获取目标对象的行为,它与 Obiect 类似,但是更易读,为操作对象提供了一种更优雅的方式。它的方法与 Proxy是对应的。
- 代替object
const obj = {};
Reflect.defineProperty(obj,'name',{
value:'kerwin',
writable: false,
configurable:false
});
- 修改某些object方法返回结果
// 老写法
try {
object.defineProperty(target, property, attributes);
// success
} catch (e) {
// fail
}
// 新写法
if (RefTect.defineProperty(target, property, attributes)) {
// success
} else {
// fail
}
- 命令式变为函数行为
const obj = {
name: "kerwin"
};//老写法
console.log(name in obj) //true
//新写法
console.log(Reflect.has(obj, 'name')) //true
//老写法
delete obj.name
//新写法
Reflect.deleteProperty(obj, "name")
- 与proxy相互照应
let arr = [1,2,3]
let proxy = new Proxy(arr,{
get(target,key){
console.log('get' ,target,key);
return Reflect.get(...arguments)
},
set(target,key,value){
console.log('set',target,key,value);
return Reflect.set(...arguments)
}
})
5.1 Promise
Promise 是异步编程的一种解决方案,比传统的解决方案回调函数,更合理和更强大。ES6 将其写进了语言标准,统一了用法,原生提供了Promise对象。
- 指定回调函数方式更灵活易懂
- 解决异步 回调地狱的问题
- 接收两个回调
let pro = new Promise(function(resolve,reject){//第一个表示下面的第一个回调函数,第二个表示第二个回调函数
setTimeout(()=>{//创建约个时间执行函数
resolve(1000)//达到要求执行函数
},1000)
})
//res表示前面函数的传参
pro.then((res)=>{
console.log('奖金',res);
}),catch((res)=>{
console.log('over',res);
})
5.2 Promise三个状态
- Promise 对象通过自身的状态,来控制异步操作。
-
- 异步操作未完成(pending)
-
- 异步操作成功(fulfilled)
-
- 异步操作失败 (rejected)
这三种的状态的变化途径只有两种。
- 从“未完成”到“成功”
- 从“未完成”到“失败”
注意:一旦状态发生变化,就凝固了,不会再有新的状态变化。这也是 Promise 这个名字的由来,它的英语意思是”承诺,一旦承诺成效,就不得再改变了。这也意味着,Promise 实例的状态变化只可能发生一次,
5.1.1 promise.all
与then同级的另一个方法,all方法,该方法提供了并行执行异步操作的能力,并且在所有异步操作执行完后并且执行结果都是成功的时候才执行回调。
运用场景
在显示页面数据的时候,等到最后一个数据加载完过后才会执行函数,到时候可以完成加载页面的消失
function promiseClick1(){
let p = new Promise(function(resolve, reject){
setTimeout(function(){
var num = Math.ceil(Math.random()*20); //生成1-10的随机数
console.log('随机数生成的值:',num)
if(num<=10){
resolve(num);
}
else{
reject('数字太于10了即将执行失败回调');
}
}, 2000);
})
return p
}
function promiseClick2(){
let p = new Promise(function(resolve, reject){
setTimeout(function(){
var num = Math.ceil(Math.random()*20); //生成1-10的随机数
console.log('随机数生成的值:',num)
if(num<=10){
resolve(num);
}
else{
reject('数字太于10了即将执行失败回调');
}
}, 2000);
})
return p
}
function promiseClick3(){
let p = new Promise(function(resolve, reject){
setTimeout(function(){
var num = Math.ceil(Math.random()*20); //生成1-10的随机数
console.log('随机数生成的值:',num)
if(num<=10){
resolve(num);
}
else{
reject('数字太于10了即将执行失败回调');
}
}, 2000);
})
return p
}
Promise
.all([promiseClick3(), promiseClick2(), promiseClick1()])
.then(function(results){
console.log(results);
});
Promise.all来执行,all接收一个数组参数,这组参数为需要执行异步操作的所有方法,里面的值最终都算返回Promise对象。这样,三个异步操作的并行执行的,等到它们都执行完后才会进到then里面。那么,三个异步操作返回的数据哪里去了呢?都在then里面,all会把所有异步操作的结果放进一个数组中传给then,然后再执行then方法的成功回调将结果接收,结果如下:(分别执行得到结果,all统一执行完三个函数并将值存在一个数组里面返回给then进行回调输出):
这样以后就可以用all并行执行多个异步操作,并且在一个回调中处理所有的返回数据,比如你需要提前准备好所有数据才渲染页面的时候就可以使用all,执行多个异步操作将所有的数据处理好,再去渲染
5.1.2 promise.race
“竞赛”的意思,谁先加载完就先执行谁的函数
运用场景:拥有三个数据库,只要有一个数据库是好的就可以完成数据的加载,防止网页崩溃
5.2 Generator函数
- Generator函数是ES6提供的一种异步编程解决方案
- Generator 函数是一个状态机,封装了多个内部状态。
- 执行 Generator 函数会返回一个遍历器对象,也就是说,Generator 函数除了状态机,还是一个遍历器对象生成函数。返回的遍历器对象,可以依次遍历 Generator 函数内部的每一个状态。
function* gen(){
console.log(11);
yield 'sad';//遇到就暂停,暂停标记,还有产出的意思
console.log(22);
yield 'asd';
console.log(33);
}
let g = gen()
let res1 = g.next()
console.log(res1);
g.next()
g.next()
return方法跟next方法的区别:
1)return终结遍历,之后的yield语句都失效;next返回本次yield语句的返回值。
2)return没有参数的时候,返回{ value: undefined, done: true };next没有参数的时候返回本次yield语句的返回值。
3)return有参数的时候,覆盖本次yield语句的返回值,也就是说,返回{ value: 参数, done: true };next有参数的时候,覆盖上次yield语句的返回值,返回值可能跟参数有关(参数参与计算的话),也可能跟参数无关(参数不参与计算)。
5.3 Class语法
基本语法:
class Person{
constructor(name,age){
this.name = name;
this.age = age;
}
Say(){
return 'My name is ' + this.name;
}
}
var person1 = new Person('Ethel',18);
console.log(person1.Say());//My name is Ethel
5.3.1 class类与原型的关系
- class类本质上就是一个函数,自身指向的就是构造函数
console.log(typeof Person);// function
console.log(Person.prototype.constructor === Person);//true
- class类是构造函数的另一种写法,仍然存在prototype方法
console.log(Person.prototype);//object
- 可以通过原型prototype修改类方法和新增方法
Person.prototype.Say = function(){
return 'My name is ' + this.name+',我是原型prototype声明同样的Say方法,把原有Say方法覆盖了';
}
person2 = new Person('Frank',20);
console.log(person2.Say());//My name is Frank,我是原型prototype声明同样的Say方法,把原有Say方法覆盖了
Person.prototype.Go = function(){
return 'I am ' + this.age + ' years old';
}
console.log(person2.Go());//I am 20 years old
- 还可以通过Object.assign方法来为对象动态增加方法
Object.assign(Person.prototype,{
Eat:function(){
return this.name;
},
Run:function(){
return this.age;
}
})
person3 = new Person('Allen',20);
console.log(person3.Eat());//Allen
console.log(person3.Run());//20
- 也可以使用实例对象的__proto__属性新增类的方法
person3 = new Person('Allen',20);
person4 = new Person('Morgan',21);
person3.__proto__.Play = function(){
return this.name;
}
console.log(person3.Play());// Allen
console.log(person4.Play());// Morgan
5.2 Class继承
- 通过extends关键字实现类的继承
class Person{
constructor(name,age){
this.name = name;
this.age = age;
}
getName(){
return this.name;
}
getAge(){
return this.age;
}
}
class Student extends Person{
getName(){
return '我覆盖了父级的方法,'+ this.name;
}
getScore(){
return '我是子级新增的方法,'+this.name;
}
}
var stu1 = new Student('Ethel',18);
console.log(sut1.getName());// 我覆盖了父级的方法,Ethel
console.log(sut1.getAge());//18
console.log(sut1.getScore());// 我是子级新增的方法,Ethel
- 通过super关键字进行拓展父类构造器或方法
super作用
子类使用构造器constructor的时候,必须使用super关键字,用来扩展构造器
子类同名方法会覆盖父类同名方法,使用super关键字后则可以调用到父类的同名函数
class Person{
constructor(name){
this.name = name;
}
getName(){
console.log('我是父级类getName方法输出来的');
}
getAge(){
console.log(this.age);
}
}
class Student extends Person{
constructor(name,age,sex){
super();//必须先调用super,才能使用constructor,才能使用this对象
this.name = name;
this.age = age;
this.sex = sex;
}
getName(){
super.getName();//调用super,才能调用父类同名函数getName
console.log('我是子级类getName方法输出来的');
}
}
var stu1 = new Student('Ethel',18);
stu1.getName();
// 我是父级类getName方法输出来的
// 我是子级类getName方法输出来的
static关键字
static关键字是类的方法
只能通过类名来调用,不能被实例对象调用
static方法也可以被继承
class Person{
constructor(name,age){
this.name = name;
this.age = age;
}
static getAge(){
console.log('我是静态属性static');
}
}
class Student extends Person{}
var stu1 = new Student('Ethel',2);
Person.getAge();//我是静态属性static
Student.getAge();//我是静态属性static
stu1.getAge();//stu1.getAge is not a function
5.3 Module
异步加载
私密不漏
重名不怕
依赖不乱
export{
***
*****
}
//导出函数
import{} from ' ./'
//导入函数
import{A1,A2,test as A_test} from ' ./'
import{B1,B2,test as b_test} from './'
//解决重名问题
export default c
//默认导出c
模块化:
js现在有两种模块。一种是ES6模块,简称ESM;另一种是commonJS模块,简称cjs
commonjs模块是nodejs专用的,与ES6模块不兼容。语法上面,两者最明显的差异是,commonjs模块使用require()和module.exports,ES6模块使用import和export
ES6模块不是对象,而实通过export命令显示指定输出的代码,再通过import命令输入
//写法1
export default A1
import a1from "./1.js"
export {A1,A2}
import {A1,A2} from "./1.js"
import {A1as a1,A2 as a2} from "./1.js"
import * as obj from "./1.js"