1998年6月,ECMAScript 2.0版发布。 1999年12月,ECMAScript 3.0版发布. 2007年10月,ECMAScript 4.0发布(最后不存在) 2009年12月,ECMAScript 5.0版正式发布。 2011年6月,ECMAscript 5.1 2015年6月17日,ECMAScript 6发布 2016年ES7发布 2017年ES8发布
ECMAScript 运算ES代码 有两个环境
1.浏览器
2.Node
也就是说 JS代码 在浏览器里面能跑 在node也能跑
node是后端
对于有些浏览器来说 对ES6及以后的版本支持并不是很友好
目前来说 对ES6支持的 就是谷歌浏览器
我们去写ES6代码的时候 如果说 其他浏览器不支持
我们需要通过某个工具 把ES6代码 转换成更为低级的ES代码(优雅降级)
目的:让我们其他浏览器更好的支持
<script>
var a=()=>{
console.log(123);
}//这是ES6中箭头函数
// 有的浏览器识别不了 那么通过优雅降级后 代码就是
function a(){
console.log(123);
}
</script>
ES6都干了什么?
这也是你面试的时候 面试官问的最多的问题之一 或者就是笔试题
ES6和ES5的区别 ES6都新增了什么 ES6都有哪些新的语法 (ES6是什么 那么首先你得解释ES6是什么 再说ES6和ES5的区别)
1.多了很多语法糖
什么是语法糖 就是一些很简便的写法 比如你的箭头函数 解构赋值 展开运算符 比如class类
2.let 和const
这两个也是es6新增的变量修饰词 let声明的变量不会提升 不能重复声明 const声明一个常量 不能改变
3.新增了很多的API
API说白了就是别人提供好的方法 或者说具有一定功能的函数 我们可以去调用
学完后端后 后端需要给前端提供API接口,那么这里的API接口 说白了
也是具有一定功能的请求地址
比如我后端写了一个增加用户的接口 那么前端调用这个接口把数据传过去
后端就可以把传过来的数据添加到数据里里面
API接口就是 别人给你准备好的具有一定功能的方法或者地址
主要是数值的 对象的 字符串的
字面意思了解的话 就是以什么开头,实际的方法的解释
1.当startsWith只有一个参数的时候
判断 一个字符串是否以某个子串开头
let url="www.baidu.com" //一个字符串
console.log(url.startsWith("s"));//false
console.log(url.startsWith("w"));//true
console.log(url.startsWith("ww"));//true
console.log(url.startsWith("www"));//true
console.log(url.startsWith("www."));//true
2.当startsWith有两个参数
查找从第二个参数为索引的位置开头的字符串 是否以第一个参数开头
let url="www.baidu.com" //一个字符串
console.log(url.startsWith("b",4));//true
console.log(url.startsWith("w",4));//false
1.当只有一个参数的时候
判断字符串是否以某个子串结尾
let url="www.baidu.com" //一个字符串
console.log(url.endsWith("com"));//true
console.log(url.endsWith("om"));//true
console.log(url.endsWith("m"));//true
console.log(url.endsWith("o"));//false
2.当startsWith有两个参数
查找从第二个参数为索引的位置开头的字符串 是否以第一个参数开头
let url="www.baidu.com" //一个字符串
console.log(url.startsWith("b",4));//true
console.log(url.startsWith("w",4));//false
1.当只有一个参数的时候
判断一个字符串中是否有某个子串
let url="www.baidu.com" //一个字符串
console.log(url.includes("www"));//true
console.log(url.includes("baidu"));//true
console.log(url.includes("com"));//true
console.log(url.includes("xxx"));//false
2.当有两个参数的时候
判断从第二个参数为索引开始的字符串是否包含第一个参数
let url="www.baidu.com" //一个字符串
console.log(url.includes("www",4));//false
console.log(url.includes("baidu",4));//true
console.log(url.includes("com",4));//true
str.repact(n) 整体的值就是重复了n次的str
let str="What"
console.log(str.repeat(10));//WhatWhatWhatWhatWhatWhatWhatWhatWhatWhat
for (let char of url) {
console.log(char);
}
let name="wangcai"
let age="100"
// 普通的字符串拼接
console.log(name+"今年"+age+"岁");//wangcai今年100岁
// ES6中的模板字符串
console.log(`${name}今年${age}岁`);//wangcai今年100岁
let num=10; //十进制
let num1=0x10 //表示十六进制 那么这个数换成十进制就是16 16+0
let num2=0b100 //0b开头表示二进制 4
let num3=0o17 //0o表示八进制 8+7=15
判断一个数字是否是NaN
let a=1;
let b=undefined;
console.log(Number.isNaN(a));//false
console.log(Number.isNaN(a+b));//true
用于检测其参数是否为最大值 如果是NaN 或者是正负无穷大的时候 返回false 否则为true
console.log(Number.isFinite(111));//true
console.log(Number.isFinite("111"));//false 移植后 这种的更为准确
console.log(isFinite("111"));//true 默认的进行一个隐式类型转换
Infinity表示无穷大
console.log(Number.isFinite(-Infinity));//负无穷 false
该函数指定字符串中首个字符是否为数字
parseFloat 没区别
如果是 则对字符串进行解析 直到到达数字结束 然后返回这个数字 说白了就是把前面的数字截下来
能把小数部分也接下来
console.log(parseFloat("100年以后"));//100
console.log(parseFloat("100.5年以后"));//100.5
console.log(parseFloat("100.555年以后"));//100.555
console.log(parseFloat("100.555年以后3.1415926"));//100.555
截取前面的数字 但是只能截取整数部分
console.log(parseInt("100.555年以后3.1415926"));//100
console.log(parseInt(10,8));//8
console.log(parseInt(11,8));//9
当有两个参数的时候 那么 就和进制扯上关系了
返回8进制的10 转换成10进制的数
console.log(parseInt("10",16));
// 返回16进制的10 转换成10进制的数 1*16+0*1
console.log(parseInt("84",9));
// 返回9进制的84 转换成10进制的数 8*9+4*1=76
console.log(parseInt("66",7));
// 返回7进制的66 转换成10进制的数 6*7+6*1=48
var fn= ()=>{
console.log("fn");
}
fn()
如果函数有一个参数 ()就可以省略不写了
如果说是多个参数 必须写
var gn=function(a){
console.log(a*2);
}
gn(2)
var gn= a=>{
console.log(a*2);
}
gn(2)
如果说函数体只有一个语句 {}花括号可以不写
var fn=function(){
// console.log(123);
// }
var fn=()=>console.log(123);
fn()
如果只有一个语句一个参数
var gn=function(a){
console.log(a*2);
}
var gn=a=>console.log(a*2);
gn(2)
如果说函数只有一条带return的语句 {}也可以不写 return也可以不写
var fn=function(a){
return a*2
}
console.log(fn(2));
var fn=a=>a*2;
console.log(fn(2));
<script>
setTimeout(function(){
console.log("xx");
},2000)
setTimeout(()=>{
console.log(xx);
},2000)
setTimeout(()=>console.log("xx"),2000)
</script>
<div>
<button>点我一下</button>
</div>
<script>
let btn=document.getElementsByTagName("button")[0];
btn.onclick=function(){
console.log(this);
console.log("点我干啥");
}
btn.onclick=()=>{
console.log(this);
console.log("点我干啥");
}
// 箭头函数中的this指向的是最大的一级 window vue中你用箭头函数 this 那么值的就是vue
</script> -->
<script>
let fn=function(){
return {a:1}
}
let fn=()=>{a:1};
// 但是你这样写的话 就分不清你这个花括号 到底是谁的花括号了
// 到底是你返回值的花括号 还是你函数的花括号
// 所以我们要写成下面的形式
let fn=()=>({a:1});
console.log(fn());
</script>
<script>
// 函数可以给形参提供默认值
function fn(a=666,b){
console.log(a,b);
}
fn()
// 如果说我只给一个实参 那么是传给了谁?
fn(1)
// 传参数是从左往右传的 所以是给了a
</script> -->
<script>
// 收集参数? argument
function fn(a,b,c,d){
console.log(arguments);
// arguments把我们的参数收集过来了
// arguments到底是不是一个数组?
console.log(Array.isArray(arguments));//false 不是数组 伪数组
}
fn(1,2,3,4)
</script>
**拓展参数
..args 整体也叫rest参数 他的作用也是收集参数
当你不确定有几个参数的时候 在参数列表 就写...args 那么你写几个都行**
function fn(...args){
// 参数进来后被收集到args里
console.log(args);
console.log(Array.isArray(args));//true
// args是一个 实打实的 数组
console.log(arguments);
}
fn(1,2)
所以说 args 要和 参数列表中的…args搭配使用
/但是 arguments 是一直有的 只要你函数调用的时候传了实参
除去给你形参赋值 还会收集参数到arguments对象上
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
* {
margin: 0;
padding: 0;
}
.wd1200 {
width: 1200px;
}
.main {
margin: 0 auto;
}
.mr20 {
margin: 20px auto;
}
.search {
text-align: center;
}
.operation {
text-align: center;
}
button {
width: 100px;
margin: 0 20px;
}
.classlist {
text-align: center;
}
.classlist ul {
list-style: none;
display: table;
width: 100%;
}
.classlist ul li {
display: table-cell;
width: 400px;
}
</style>
</head>
<body>
<div class="wd1200 main">
<div class="search mr20">
<label for="name">姓名</label>
<input type="text" name="name" id="name">
<label for="sid">学号</label>
<input type="text" name="sid" id="sid">
<label for="sclass">班级</label>
<input type="text" name="sclass" id="sclass">
</div>
<div class="mr20 operation">
<button id="add">添加</button>
<button id="searchStudent">查找</button>
</div>
<div class="classlist mr20" id="classlist">
<ul>
<li>姓名</li>
<li>学号</li>
<li>班级</li>
</ul>
</div>
</div>
</body>
<script>
let add = document.getElementById("add");
let name = document.getElementById("name")
let sid = document.getElementById("sid")
let sclass = document.getElementById("sclass")
let classlist = document.getElementById("classlist")
let search = document.getElementById("searchStudent")
let studentList = []
class Student {
constructor(name, id, sclass) {
this.name = name;
this.id = id;
this.sclass = sclass;
}
}
// 模拟数据
let stu1 = new Student("张三", "14258", "绘画1")
let stu2 = new Student("李四", "14259", "绘画2")
let stu3 = new Student("王五", "14260", "绘画1")
let stu4 = new Student("赵六", "14291", "绘画2")
studentList.push(stu1)
studentList.push(stu2)
studentList.push(stu3)
studentList.push(stu4)
// 添加学生
add.onclick = function () {
// 现在想让这个学生就是一个新的对象
let stu = new Student(name.value, sid.value, sclass.value);
studentList.push(stu)
let str = `
${stu.name}${stu.id}${stu.sclass}`
let allStr = classlist.innerHTML;
allStr = allStr + str;
classlist.innerHTML = allStr;
}
// 上来想把这个模拟数据塞进去
// 当也加载完的时候调用
// 模拟数据回显
window.onload = function () {
studentList.forEach(item => {
let str = `
${item.name}${item.id}${item.sclass}`
let allStr = classlist.innerHTML;
allStr = allStr + str;
classlist.innerHTML = allStr;
});
}
// 查找
search.onclick = () => {
let allStr=`- 姓名
- 学号
- 班级
`
console.log(sclass.value);
let res = studentList.filter(function (item) {
return item.sclass == sclass.value
})
res.forEach(item => {
let str = `
${item.name}${item.id}${item.sclass}`
allStr = allStr + str;
classlist.innerHTML = allStr;
})
}
</script>
</html>
伪数组 又叫类数组
长的 像数组 但不是数组, 是对象
对象的键值对 键比较特殊 {name:“Wc”}
let arr={
"0":"A",
"1":"B",
"2":"C",
"3":"D",
length:4
}
如何去判断他到底是不是数组
console.log(Array.isArray(arr));//false
1)我们获取的DOM元素,实际上,document.getElementsByTagName 得到的实际上就是一个伪数组
2)在函数内部有一个arguments 他也是一个伪数组
在es6中,提供了一个方法 可以把伪数组转换成一个真的数组
在这里Array是对象
let arr={
"0":"A",
"1":"B",
"2":"C",
"3":"D",
length:4
}
Array.from(参数) 参数即是你像转换成真的数组的伪数组
let res=Array.from(arr);
console.log(res);
console.log(Array.isArray(res));//true
实际上在ES6中 对数组的拓展 主要就体现在对伪数组和数组API中
如果现在有一个类,但是我现在只想要 对象中的属性名,将这些属性名单独的放到一个数组中
let obj={
name:"zhangsan",
age:"18",
srore:"99",
address:"bj",
length:4
}
第一反应是循环这个对象,然后用push方法把他放进去
但是在ES6中,提供了一个方法 不需要循环
console.log(Object.keys(obj));//["name", "age", "srore", "address", "length"]
let obj={
name:"zhangsan",
age:"18",
srore:"99",
address:"bj",
length:4
}
如何把他的属性值单独的放到一个数组里面
console.log(Object.values(obj));//["zhangsan", "18", "99", "bj", 4]
let obj={
name:"zhangsan",
age:"18",
srore:"99",
address:"bj",
length:4
}
console.log(Object.keys(obj));
console.log(Object.values(obj));
let objValue=Object.values(obj)
// 想让他循环输出 很简单
for (let index in objValue) {
console.log(objValue[index]);
}
let obj={
name:"zhangsan",
age:"18",
srore:"99",
address:"bj",
length:4
}
// [[a],[b],[c]] 二维数组
// [[[a]]] 三维数组
// 如何循环一个二维数组?
// for循环嵌套
let arr=[[1,2],[3,4],[5,6]];
for (let v1 of arr) {
for(let v2 of v1){
console.log(v2);
}
}
这个方法把 一个对象中的属性名和属性值放到了一个数组
然后又把每条属性放到了一个数组
让一个对象 变成了一个二维数组
let arr=[[1,2],[3,4],[5,6]];
for (let v1 of arr) {
for(let v2 of v1){
console.log(v2);
}
}
console.log(Object.entries(obj));
for(let v1 of Object.entries(obj)){
for(let v2 of v1){
console.log(v2);
}
}
编程 有两种方式:
1.声明式编程 命名式编程
声明式编程就是人家写好的 你拿过来用 人家让 你怎么用 你就怎么用
2.命名式编程 你自己写 你想怎么写 就怎么写
for (let index = 0; index < array.length; index++) {
const element = array[index];
}
for (const key in object) {
if (Object.hasOwnProperty.call(object, key)) {
const element = object[key];
}
}
for (const iterator of object) {
}
作用是什么?
在一个数组中查找满足条件的第一个元素
let arr=[1,2,3,4,5,6,7]
let res=arr.find(function(item){
return item>2;
})
let res1=arr.find(item=>item>3)
console.log(res);
console.log(res1);
arr.find 在arr中寻找 满足return后面条件的第一个元素并返回这个元素 find函数的参数是一个回调函数
找到数组中满足条件的第一个元素的索引,整体的返回值是我们的索引
let arr=[1,2,3,4,5];
let res=arr.findIndex(function(item){
return item>2;
})
let res1=arr.findIndex(item=>item>4)
console.log(res);
console.log(res1);
判断一个元素是否在数组中
let arr=[1,2,3,4,5];
console.log(arr.includes(2));
console.log(arr.includes(20));
对数组中的每个元素进行加工, 返回一个加工后的新的数组
let arr=[1,2,3,4,5];
// 想得到一个新的数组 数组中的每一项是arr中每一项的二倍
// map有映射的意思
let res=arr.map(function(item){
return item*2;
})
console.log(res);
是对数组进行过滤的
find是查找到满足条件的第一个元素, 那这个filter就是找到所有满足条件的元素并将它们放到一个新的数组 然后返回
let arr=[1,2,3,4,5];
let res=arr.filter(function(item){
return item>2;
})
console.log(res);
只有你数组中每一个元素都满足这个条件 返回值为true 否则为false
let arr=[1,2,3,4,5];
let res=arr.every(function(item){
return item == 1
})
console.log(res);
这个数组中 只要有一个满足条件 那么他的返回值就是true
let arr=[1,2,3,4,5];
let res=arr.some(function(item){
return item<1
})
console.log(res);
遍历数组:
1)for循环
2)forEach
3)for in
4)for of
遍历对象:
1)for in
2)Object.keys
3)Object.values
4)Object.entries
一些方法:这里面有ES5有ES6:
find:在一个数组中找到满足条件的第一个元素 并返回这个元素 如果没有则返回undefined
findIndex:在一个数组中找到满足条件的第一个元素并返回这个元素的索引 如果没有则返回-1
includes:判断一个数组中是否包含某个元素 如果包含则返回true否则false
map:对数组中的每一个元素进行加工 返回一个加工后的新数组
filter:对数组中每一个元素进行过滤 返回过滤后的新数组
some:遍历数组中的每一个元素,只要有一个元素满足条件,则返回true 并且立即停止遍历
every:遍历数组中的每一个元素 所有元素都满足条件后 返回true 有一个不满足就返回else 并停止遍历
let obj={
name:"wc",
age:100
}
let name="wc";
let age=18;
let obj={
name:name,
age:age
}
当你的属性名和属性值相同的时候 就可以直接简写
let name = "wc";
let age = 18;
// 方法可以简写吗?
let obj = {
name,
age,
say(){
console.log("say..");
}
}
console.log(name);
console.log(age);
obj.say();
Object.assign可以将这两对象合为一起
参数1 {} 目标对象 参数2 参数3…源对象
把源对象上面的属性 统统赋值给目标对象
let obj2={age:100}
let obj={}
console.log(Object.assign(obj,obj1,obj2));
console.log(obj);
let arr1=[1,2,3]
let arr2=[4,5,6]
let arr3=[...arr1,...arr2]
console.log(arr3);
切记 属性名相同的时候 后面的会覆盖**
let obj1={name:"zhangsan",age:"18"}
let obj2={name1:"lisi",age1:"19"}
let obj3={...obj1,...obj2}
console.log(obj3);
function gn(){
console.log(arguments);
console.log(...arguments);
}
gn(1,2,3,4)
// 可变参数
function gn(...args){
console.log(args);
}
// 你有几个参数都可以
gn(1,2,3)
解构赋值就是一种很简单的赋值方式
let arr=["wc","xq","zs"];
// 想给a1赋值为wc 给a2赋值为sq 给a3赋值为zs
// 老方法是
// let a1=arr[0]
// let a2=arr[1]
// let a3=arr[2]
// 看如下解构赋值的写法
let [a1,a2,a3]=["wc","xq","zs"];
let [a1,a2,a3]=arr;
console.log(a1,a2,a3);
你要用结构赋值 必须保持 =两边的数据类型 要保持一致
// 交换两个数字的位置
let a=1;
let b=2;
// 现在我想让a是b的值2 b是a的值1
let c;
c=a;
a=b;
b=c;
console.log(a,b);
let b=2;
// 解构赋值中交换两个数
[a,b]=[b,a]
console.log(a,b);
如果说一个数组中有三个数,但是我解构赋值只想给后两个 或者后一个赋值
let [,b,a]=[1,2,3]
console.log(b,a);
let [c,,d]=[1,2,3]
console.log(c,d);
解构赋值 能用于数组, 也可以用于对象
let obj={
name:"zhangsan",
age:"18"
}
let {name,age}=obj;
// 通过解构赋值的方式 给我的变量赋值
console.log(name,age);
切记一点 就是对象的解构赋值的时候不要加名字 不要起别名
{name:username,age:userage}={name:"wc",age:"100"}
// 这里的username 和 userage就是别名
console.log(name,age);//会报错
let {name,age,score}={name:"wc",age:100}
// score 没有解构出来的数据 默认的就是undefined
// console.log(score);//undefined
let {name,age,score=99}={name:"wc",age:100}
console.log(score);
学这个之前 我们的类 通常是函数 也叫构造器
但是在ES6 多了一个新的声明方式 叫class 专门用于声明类
function Father(name){
this.name=name
// }
class Fahter{
}
// class用于声明一个类 这里的话 我们的Father就是一个类 而f就是一个对象
let f=new Father();
当我们new的时候就会自动的调用constructor这个函数
在constructor中可以给对象添加私有属性了
class Father{
// 在这里面我们有一个默认的函数 叫constructor
// 当我们new的时候就会自动的调用constructor这个函数
// 在constructor中可以给对象添加私有属性了
// 比如我现在这个Fahter类中有私有属性name和age
constructor(name,age){
this.name=name;//私有属性name
this.age=age;//私有属性age
this.say=function(){//私有方法say
console.log("say...");
}
console.log("构造函数被调用了");
}
}
let f=new Father("wc",100);
console.log(f);//这个f是father类的对象
f.say();
私有方法和私有属性都写了 公有的怎么办
class Father{
constructor(name,age){
this.name=name;
this.age=age;
console.log("构造函数被调用了");
}
// 在constructor外面声明公有属性
// 以前还得去prototype上写
// 现在可以直接在这里写
jump(){
console.log("jump");
}
}
let f=new Father("zhangsan","18");
console.log(f);
f.jump();
// 为了再次验证我这个是在公有属性上的
console.log(f.__proto__);
// 如何查看自己私有属性里面有没有某一个呢?
// 当前我的这个对象 有两个私有属性 分别是 name age 一个公有属性 jump
console.log(f.hasOwnProperty("name")); //true
console.log(f.hasOwnProperty("age")); //true
console.log(f.hasOwnProperty("jump")); //false
// 如何判断你有没有这个属性 包括公有和私有
console.log("name" in f);//true
console.log("age" in f);//true
console.log("jump" in f);//true
console.log("jumps" in f);//false
class Father{
static score=100; //静态属性 设置在Father对象上的
constructor(name,age){
this.name=name;
this.age=age;
this.say=function(){
console.log("say..");
}
}
jump(){
console.log("jump..");
}
static haha(){
console.log("haha");
}
}
static 静态属性
静态的属性怎么去用
静态修饰的属性方法 都需要通过类名调用 不能通过对象名调用
et f=new Father("zhangsan","18");
console.log(f.score);//undefined
console.log(Father.score);//100
// f.haha()//f.haha is not a function
Father.haha();//haha
</script> -->
以前讲继承 原形继承 call继承 组合继承 只继承共有属性
在ES6中如何继承?
class Father{
constructor(){
this.a=100;
}
getA(){
console.log(this.a);
}
}
Son中没有私有属性 没有共有属性
但是 想继承父级的 用Father里面的公有属性和私有属性
class Son extends Father{};
let son=new Son();
console.log(son.a);//100
son.getA();//100
<script>
class Father{
constructor(){
this.job="student";
}
getA(){
console.log(this.a);
}
}
class Son extends Father{
// 我现在子类不满足了 因为我继承父类后 我应该有一些自己的属性
// 我除了job 我还有一个自己的私有属性 name
constructor(name){
// 你现在既要给自己的私有属性赋值 又要用父级继承过来的job
super();
// 这个super 按我的理解 就像调用了 父级里面的构造函数一样
this.name=name;
}
getA(){
console.log("Son中的getA");
}
}
let son=new Son("zhangsan");
console.log(son);
son.getA()
</script>
)Set 不是对象{} 也不是数组 是一个新的数据解构
2)Map
我们以前说 对象 数组啊 可以通过let a=new Array()去生成
我们这个set和map也是
let mySet=new Set();
在这里mySet是对象 Set是类
如何往里面这个Set容器里面放东西
mySet.add("张三")
console.log(mySet);//{"张三"}
mySet.add("李四")
console.log(mySet);//{"张三", "李四"}
这个set容器有一个特点 就是你往里面放东西 放重复的 他不会加
mySet.add("张三")
console.log(mySet);//{"张三", "李四"}
console.log(mySet.size);//2
mySet.delete("张三");
console.log(mySet);//{"李四"}
mySet.add("张三")
console.log(mySet.has("张三"));//true
console.log(mySet.has("王麻子"));//false
mySet.clear();
console.log(mySet);//{}
mySet.add("李四");
mySet.add("张三");
mySet.add("王麻子");
console.log(mySet);
for (let item of mySet) {
console.log(item);
}
普通的Set 里面存的都是字符串 数字啊 基础数据类型
WeakSet里面存的是引用数据类型
let myWeakSet=new WeakSet();
myWeakSet.add({name:"zhangsan"})
myWeakSet.add({name:"李四"})
myWeakSet.add([1,2,3])
console.log(myWeakSet);
Map也是ES6中新增的一个容器 它里面存的是键值对
学容器 说白了就是学增删改查 以前学数组的时候 开始也是增删改查 学对象的时候也是
了解:可迭代对象 只要是一个可迭代对象 都可以用for of来遍历
在JS中下面的几个类型是可以迭代的
Array
Set
Map
String
你通过构造器创建出来上面的这几个对象 都叫可迭代对象
只有可迭代对象 才能用for of进行遍历
let arr=new Array("a","b","c","d")
// 这个arr是对象 由于他是Array创造出来的 所以叫可迭代对象
// 那么可以用for of遍历
for (const item of arr) {
console.log(item);
}
遍历对象
forin Objcet.keys Object.values Object.entries
迭代器是专门用于迭代对象 所有的可迭代对象都有一个方法 叫做next方法
用这个next方法的话 会返回一个对象 这个对象里面有两个属性 一个叫value 一个叫done
alue表示当前迭代出来的值 done则表示是否迭代完毕 如果完毕 done的值就是true
生成器:生成迭代器 generator是生成器的意思
(如果在你的function 和 函数名之间 加了一个 那么此时这就是一个生成器)*
function *generator(){
// 如果是普通函数 当我们调用的时候 代码就会立即全部执行
// 但是如果是生成器的话 你就可以让代码分步执行
// 在生成器里面 产出数据
yield "v1"
// 我们调用生成器 产生一个迭代器
let it=generator();
console.log(it.next());//{value: "v1", done: false}
// 每调用一次next()那么他就会迭代一次
console.log(it.next());//{value: undefined, done: true}
// 写一个生成器
function *app(){
yield "v1"
yield "v2"
yield "v3"
yield "v4"
}
let it=app();
console.log(it.next());//{value: "v1", done: false}
console.log(it.next());
console.log(it.next());
console.log(it.next());
console.log(it.next());//value: undefined, done: true
//true表示迭代完成
function *app(){
let s1=yield "v1"
console.log("s1:",s1);
let s2=yield "v2"
console.log("s2:",s2);
let s3=yield "v3"
console.log("s3:",s3);
let s4=yield "v4"
console.log("s4:",s4);
}
let it=app();
// 在调用next的时候 可以给生成器内容变量赋值
// 传参的话 第一次传的参数 没有用
console.log(it.next("张三"));
console.log(it.next("张三"));
console.log(it.next("李四"));
console.log(it.next("王五"));
console.log(it.next("赵六"));
在调用next的时候 可以给生成器内容变量赋值
传参的话 第一次传的参数 没有用
小结:
生成器的作用:用于生成迭代器
迭代器:主要是迭代出对象 数据可以在生成器中产出
可迭代对象 :内置了迭代器 使用for of就可以迭代