ES6-11(第一部分)
ECMA
- ECMA是一个组织
- ECMAScript是由Ecma国际通过ECMA-262标准化的脚本程序设计语言
- Ecma国际指定了很多标准,ECMA-262只是其中之一
- TC39定期开会维护ECMA-262
ES6
let:
let
是 ES6 中引入的一种新的变量声明方式,用于声明块级作用域的变量。它与之前 JavaScript 中的var
关键字有着重要的区别。let
和var
的区别作用域:
var
声明的变量具有函数级作用域,这意味着它们可以在函数内部的任何地方访问,即使是在声明之前。let
声明的变量具有块级作用域,这意味着它们只能在声明所在的代码块({}
之间)内访问。
重复声明:
var
允许在同一个作用域内重复声明同一个变量,后面的声明会覆盖前面的声明。let
不允许在同一个作用域内重复声明同一个变量,这会抛出一个SyntaxError
。
提升:
var
声明的变量会进行提升,这意味着可以在声明之前访问它们,但访问的值是undefined
。let
声明的变量不会进行提升,在声明之前访问它们会导致ReferenceError
。
使用
let
的优势- 避免意外的变量覆盖:
let
阻止了在同一作用域内重复声明变量,从而避免了意外的变量覆盖。 - 更清晰的代码逻辑:
let
的块级作用域使得代码逻辑更清晰,更容易理解变量的作用范围。 - 减少全局变量的使用:
let
的使用鼓励使用局部变量,从而减少了对全局变量的依赖,使代码更易于维护。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>let</title> </head> <body> <script> //声明变量 let a; let b,c,d; let e=100; let f=521,g='iloveyou',h=[]; //1.变量不能重复声明 // let star='star'; // let star='xx'; //2.块级作用域 全局,函数,eval //if else while for // { // let name='john'; //用var可以 // } // console.log(name); //3.不存在变量提升 就是在下面声明的变量上面可以知道它的存在不会报错,用var才可以 // console.log(song); // let song='恋爱达人' //4.不影响作用域链 就是在函数中没有声明这个变量,就会向上一级作用域找,找到就可以正常运行 { let school='学校'; function fn(){ console.log(school); } fn(); } </script> </body> </html>
let实践案例
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <!-- CSS --> <link href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/4.6.2/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-xOolHFLEh07PJGoPkLv1IbcEPTNtaed2xpHsD9ESMhqIYd0nLMwNLD69Npy4HI+N" crossorigin="anonymous"> <style> .item{ width: 100px; height: 80px; border: 2px solid green; float: left; } </style> </head> <body> <div class="container"> <h2 class="page-header">点击切换颜色</h2> <div class="item"></div> <div class="item"></div> <div class="item"></div> </div> <script> //获取div元素对象 let items=document.getElementsByClassName('item'); // //遍历并绑定事件 用ar声明i变量 // for(var i=0;i<items.length;i++){ // items[i].οnclick=function(){ // //修改当前元素的背景颜色 // // this.style.background='pink'; // items[i].style.background='pink';//var声明i时不可用,因为先遍历items数组,后点击,i为3,不存在i为3的元素,所以不可用 // } // } // console.log(window.i);//i为3,因为var声明变量,所以是全局的,在外面也能读取到 //遍历并绑定事件 用let声明i变量 for(let i=0;i<items.length;i++){ items[i].onclick=function(){ //修改当前元素的背景颜色 // this.style.background='pink'; items[i].style.background='pink';//let声明i时可用,因为是局部块级变量,所以i在函数中没有声明的时候会向上一级作用域找,就找到了对应的i } } </script> </body> </html>
const:值不能修改的量称常量
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>const 定义常量</title> </head> <body> <script> //声明常量 const SCHOOL='学校'; //1.一定要赋初始值 // const A; //2.一般常量使用大写(潜规则) // const a=100; //3.常量的值不能修改 // SCHOOL='school'; //4.块级作用域 // { // const PLAYER='Hoshi'; // } // console.log(PLAYER); //5.对于数组和对象的元素修改,不算做对常量的修改,不会报错,因为常量指向的地址没有修改 // const TEAM=['hoshi','woozi','jww','jun']; // TEAM.push('scoups'); // TEAM=100;//会报错 </script> </body> </html>
结构赋值:ES6允许按照一定模式从数组和对象中提取值,对变量进行赋值,这称为结构赋值
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>变量的解构赋值</title> </head> <body> <script> //ES6允许按照一定模式从数组和对象中提取值,对变量进行赋值,这称为结构赋值 //1.数组的解构 // const F4=['xiao','liu','zhao','song']; // let [xiao,liu,zhao,song]=F4; // console.log(xiao); // console.log(liu); // console.log(zhao); // console.log(song); //2.对象的解构 const zhao={ name:'zhaobenshan', age:'none', xiaopin:function(){ console.log('i can play'); } }; // let {name,age,xiaopin}=zhao; // console.log(name); // console.log(age); // console.log(xiaopin); // xiaopin(); let {xiaopin}=zhao; xiaopin(); </script> </body> </html>
模板字符串:``
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>模板字符串</title> </head> <body> <script> //ES6引入新的声明字符串的方式 `` '' "" //1.声明 // let str=`我是一个字符串`; // console.log(str,typeof str);//我是一个字符串 string //2.内容中可以直接出现换行符 `` let str=`<ul> <li>hoshi</li> <li>woozi</li> <li>jun</li> </ul>`; //3.变量拼接 let lovest='hoshi'; let out=`${lovest}woozi`; console.log(out); </script> </body> </html>
简化对象写法
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>简化对象写法</title> </head> <body> <script> //ES6允许再打括号里面直接写入变量和函数,作为对象的属性和方法 //这样书写更加简洁 let name='hoshi'; let change=function(){ console.log('change you'); } const school={ name,//等同于name:name change,//等同于change:change // improve:function(){ // console.log('improve you'); // } improve(){//可以简写成这样 console.log('improve you'); } } console.log(school); </script> </body> </html>
箭头函数
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>箭头函数</title> </head> <body> <script> //ES6允许使用箭头 => 定义函数 //声明一个函数 // let fn=function(){ // } // let fn=(a,b)=>{ // return a+b; // } // //调用函数 // let result=fn(1,2); // console.log(result); //1.this是静态的.this始终指向函数声明时所在的作用域下的this的值 function getName(){ console.log(this.name); } let getName2=()=>{ console.log(this.name); } //设置window对象的name属性 window.name='hoshi'; const school={ name:'woozi' } //直接调用 // getName();//hoshi // getName2();//hoshi //call方法调用 // getName.call(school);//woozi // getName2.call(school);//hoshi //2.不能作为构造实例化对象 // let Person=(name,age)=>{ // this.name=name; // this.age=age; // } // let me=new Person('xiao',30); // console.log(me);//会报错 //3.不能使用arguments变量 // let fn=()=>{ // console.log(arguments); // } // fn(1,2,3); //4.箭头函数的简写 //1)省略小括号,当形参有且只有一个的时候 // let add=n=>{ // return n+n; // } // console.log(add(9)); //2)省略花括号,当代码体只有一条语句的时候,此时return必须省略,而且语句的执行结果就是函数的返回值 let pow=n=> n*n; console.log(pow(8)); </script> </body> </html>
箭头函数实践:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>箭头函数实践</title> <style> div{ width: 200px; height: 200px; background-color: #58a; } </style> </head> <body> <div id="ad"></div> <script> //需求-1 点击div 2s后颜色变为粉色 //获取元素 let ad=document.getElementById('ad'); //绑定事件 ad.addEventListener('click',function(){ //第一中方法:保存this的值 // let _this=this; //定时器 // setTimeout(function(){ // //修改背景颜色 this // // console.log(this);//指的window // _this.style.background='pink'; // },2000); //定时器 setTimeout(()=>{ //修改背景颜色 this // console.log(this);//指的是事件源ad this.style.background='pink'; },2000); }) //需求-2 从数组中返回偶数的元素 const arr=[1,6,9,10,100,25]; //原方法:使用函数 // const result=arr.filter(function(item){ // if(item%2===0){ // return true; // }else{ // return false; // } // }); // console.log(result); // const result=arr.filter(item=>{ // if(item%2===0){ // return true; // }else{ // return false; // } // }) const result=arr.filter(item=>item%2===0); console.log(result); //箭头函数适合与this无关的回调比如定时器,数组的方法回调 //箭头函数不适合与this有关的回调,比如dom事件回调,对象的方法 // 比如: // { // name:'hoshi', // getName:function(){ // this.name;//这个this指向这个花括号对象 // } // } // { // name:'woozi', // getName:()=>{ // this.name;//这个this指向外层作用域的this值 // } // } </script> </body> </html>
参数默认值
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>参数默认值</title> </head> <body> <script> //ES6允许给函数参数赋值初始值 //1.形参初始值 具有默认值的参数,一般位置要靠后(潜规则) // function add(a,b,c=10){ // return a+b+c; // } // let result=add(1,2); // console.log(result); //2.与解构赋值结合 可以设置默认值 function connect({host="127.0.0.1",username,password,port}){ console.log(host); console.log(username); console.log(password); console.log(port); } connect({ host:'localhost', username:'root', password:'root', port:3306 }) </script> </body> </html>
rest参数
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>rest参数</title> </head> <body> <script> //ES6引入rest参数,用于获取函数的实参,用来代替arguments //ES5获取实参的方式 // function date(){ // console.log(arguments);//获得的是一个对象 // } // date('hoshi','woozi','jun'); //rest参数 // function date(...args){ // console.log(args);//获取到的是数组,可以使用filter some every map方法 // } // date('hoshi','woozi','jun'); //rest参数必须放到参数最后 function fn(a,b,...args){ console.log(a);//单独输出 console.log(b);//单独输出 console.log(args);//数组输出 } fn(1,2,3,4,5,6); </script> </body> </html>
spread扩展运算符:…
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>扩展运算符</title> </head> <body> <script> // ...扩展运算符能将数组转换为逗号分隔的参数序列 //声明一个数组... const hippop=['jww','vernon','scoups','jmk'];//用...转换为 'jww','vernon','scoups','jmk' //声明一个函数 function chunwan(){ console.log(arguments); } //chunwan(hippop);//只有一个参数 chunwan(...hippop);//等同于chunwan('jww','vernon','scoups','jmk')有四个参数 </script> </body> </html>
扩展运算符应用:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>扩展运算符应用</title> </head> <body> <div></div> <div></div> <div></div> <script> //1.数组的合并 // const couple=['jun','jww']; // const partner=['jmk','jww']; // // const sum=couple.concat(partner); // const sum=[...couple,...partner];// ["jun", "jww", "jmk", "jww"] // console.log(sum); //2.数组的克隆 // const couple=['jun','jww']; // const partner=[...couple];// ["jun", "jww"] 浅拷贝 // console.log(partner); //3.将为数组转为真正的数组 // const divs=document.querySelectorAll('div'); // const divArr=[...divs]; // console.log(divArr);//也可以转为arguments </script> </body> </html>
Symbol基本使用
ES6引入了一种新的原始数据类型Symbol,表示独一无二的值。它是JavaScript语言的第七种数据类型,是一种类似于字符串的数据类型。
Symbol特点:
1)Symbol的值是唯一的,用来解决命名冲突的问题
2)Symbol值不能与其他数据进行计算
3)Symbol定义的对象属性不能使用for…in循环遍历,但是可以使用Reflect.ownKeys来获取对象的所有键名
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>symbol</title> </head> <body> <script> //创建Symbol let s=Symbol(); // console.log(s,typeof s); let s2=Symbol('hoshi'); let s3=Symbol('hoshi'); console.log(s2===s3);//false //Symbol.for创建 let s4=Symbol.for('woozi'); let s5=Symbol.for('woozi'); console.log(s4===s5); //不能与其他数据进行运算 // let result=s+100; // let result=s>100; // let result=s+s; //USONB u so nb // u undefined // s string Symbol // o object // n null number // b boolean </script> </body> </html>
Symbol创建对象属性:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Symbol 创建对象属性</title> </head> <body> <script> //向对象中添加方法up down let game={} //声明一个对象 // let methods={ // up:Symbol(), // down:Symbol() // }; // game[methods.up]=function(){//向game中添加up方法 // console.log('i can change the type'); // } // game[methods.down]=function(){//向game中添加down方法 // console.log('i can quick down'); // } // console.log(game); //利用 Symbol 的唯一性,将 say 和 zibao 方法隐藏在对象中,避免了与其他属性名冲突,并增强了代码的安全性。 let youxi={ name:'狼人杀', [Symbol('say')]:function(){ console.log('i can say'); }, [Symbol('zibao')]:function(){ console.log('i can zibao'); } } console.log(youxi); </script> </body> </html>
Symbol的内置属性:
除了定义自己使用的Symbol值以外,ES6还提供了11个内置的Symbol值,指向语言内部使用的方法。
Symbol.hasInstance:当其他对象使用instanceof运算符,判断是否为该对象的实例时,会调用这个方法。
Symbol.isConcatSpreadable:对象的Symbol.isConcatSpreadable属性等于的是一个布尔值,表示该对象用于Arrayprototype.cancat()时,是否可以展开。
Symbol.unscopables:该对象制定了使用with关键字时,哪些属性会被with环境排除。
Symbol.match:当执行str.match(myObject)时,如果该属性存在,会调用它,返回该方法的返回值。
Symbol.replace:当该对象被str.replace(myObject)方法调用时,会返回该方法的返回值。
Symbol.search:当该对象被str.search(myObject)方法调用时,会返回该方法的返回值。
Symbol.split:当该对象被str.split(myObject)方法调用时,会返回该方法的返回值。
Symbol.iterator:对象进行for…of循环时,会调用Symbol.iterator方法,返回该对象的默认遍历器。
Symbol.toPrimtive:该对象被转为原始类型的值时,会调用这个方法,返回该对象对应的原始数据类型值。
Symbol.toStringTag:在该对象上面调用toString方法时,返回该方法的返回值。
Symbol.species:创建衍生对象时,会使用该属性。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Symbol内置属性</title> </head> <body> <script> //Symbol.hasInstance // class Person{ // static [Symbol.hasInstance](param){//instanceof前面的那个值传作参数 // console.log(param); // console.log('我被用来检测类型了'); // return false; // } // } // let o={}; // console.log(o instanceof Person); //Symbol.isConcatSpreadable const arr=[1,2,3]; const arr2=[4,5,6]; arr2[Symbol.isConcatSpreadable]=false; console.log(arr.concat(arr2));//arr2会以数组形式加入到arr中,arr的长度为4 // Array(4) // 0: 1 // 1: 2 // 2: 3 // 3: (3) [4, 5, 6, Symbol(Symbol.isConcatSpreadable): false] // length: 4 </script> </body> </html>
迭代器:迭代器(Iterator)是一种接口(其实就是对象的一个属性,属性名为Symbol.Iterator),为各种不同的数据结构提供统一的访问机制。任何数据解构只要部署Iterator接口,就可以完成遍历操作。
1)ES6创造了一种新的遍历命令for…of循环,Iterator接口主要供for…of消费
2)原生具备Iterator接口的数据(可用for of遍历)
a)Array
b)Arguments
c)Set
d)Map
e)String
f)TypedArray
g)NodeList
3)工作原理
a)创建一个指针对象,指向当前数据解构的起始位置
b)第一次调用对象的next方法,指针自动指向数据结构的第一个成员
c)接下来不断调用next方法,指针一直向后移动,直到指向最后一个成员
d)每调用next方法返回一个包含value和done属性的对象
注:需要自定义遍历数据的时候,要想到迭代器
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>迭代器</title> </head> <body> <script> //声明一个数组 const xiyou=['tangseng','swk','zbj','ss']; //使用for...of遍历数组 // for(let v of xiyou){ // console.log(v);//键值 即tangseng... // } // //使用for...in遍历 // for(let v in xiyou){ // console.log(v);//键名 0 1 2 3 // } // console.log(xiyou); let iterator=xiyou[Symbol.iterator](); //调用对象的next方法 console.log(iterator.next()); console.log(iterator.next()); console.log(iterator.next()); console.log(iterator.next()); console.log(iterator.next()); </script> </body> </html>
迭代器自定义遍历对象:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>自定义遍历数据</title> </head> <body> <script> //声明一个对象 const banji={ name:"终极版", stus:[ 'hoshi', 'woozi', '2gg', 'shua' ], [Symbol.iterator](){ //索引变量 let index=0; //保存this let _this=this; return { next:function(){ if(index<_this.stus.length){ const result= { value:_this.stus[index],done:false}; //下标自增 index++; //返回结果 return result; }else{ return {value:undefined,done:true}; } } }; } } //遍历这个对象 for(let v of banji){ console.log(v); } </script> </body> </html>
生成器函数:生成器函数是ES6提供的一种异步编程解决方案,语法行为与传统函数完全不同
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>生成器</title> </head> <body> <script> //生成器其实就是一种特殊的函数 //异步编程 纯回调函数 node fs ajax mongodb //yield函数代码分隔符 function * gen(){ // console.log("111"); yield 'hoshi'; // console.log("222"); yield 'woozi'; // console.log("333"); yield 'jun'; // console.log("444"); } let iterator=gen(); // console.log(iterator);//是一个迭代器对象 // iterator.next();//执行函数 111 // iterator.next();//执行函数 222 // iterator.next();//执行函数 333 // iterator.next();//执行函数 444 console.log(iterator.next());//执行函数 对象{value:'',done:false} console.log(iterator.next());//执行函数 console.log(iterator.next());//执行函数 console.log(iterator.next());//执行函数 //遍历 for(let v of gen()){ console.log(v);//111 hoshi... } </script> </body> </html>
生成器函数参数:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>生成器函数参数</title> </head> <body> <script> function * gen(args){ console.log(args);//AAA let one=yield 111; console.log(one);//BBB let two=yield 222; console.log(two);//CCC let three=yield 333; console.log(three);//DDD } //执行获取迭代器对象 let iterator=gen('AAA'); console.log(iterator.next()); //next方法可以传入实参 console.log(iterator.next('BBB')); console.log(iterator.next('CCC')); console.log(iterator.next('DDD')); </script> </body> </html>
生成器函数实例-1:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>生成器函数实例-1</title> </head> <body> <script> //异步编程 文件操作 网络操作(ajax,request)数据库操作 //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(); </script> </body> </html>
生成器函数实例-2:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>生成器函数</title> </head> <body> <script> //模拟获取 用户数据 订单数据 商品数据 function getUsers(){ setTimeout(()=>{ let data='用户数据'; //调用next方法,并且将数据传入 iterator.next(data); },1000); } function getOrders(){ setTimeout(()=>{ let data='订单数据'; //调用next方法,并且将数据传入 iterator.next(data); },1000); } function getGoods(){ setTimeout(()=>{ let data='商品数据'; //调用next方法,并且将数据传入 iterator.next(data); },1000); } function * gen(){ let users=yield getUsers(); console.log(users); let orders=yield getOrders(); console.log(orders); let goods=yield getGoods(); console.log(goods); } //调用生成器函数 let iterator=gen(); iterator.next(); </script> </body> </html>