IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> JavaScript知识库 -> ES6-01 -> 正文阅读

[JavaScript知识库]ES6-01

?目录

1.ES6. 3

1.1ECMAScript发展历史: 3

1.2ES6简介... 3

2.关键字... 3

2.1 let关键字... 3

2.2 let与var比较... 4

2.2const关键字... 5

3.字符串拓展... 7

3.1多行字符串... 7

3.1.1单行字符串: 7

3.1.2多行字符串... 7

3.2原始字符串(String.raw)... 8

3.3重复字符串(repeat)... 9

3.4判断字符串位置... 9

4.数字拓展... 10

4.1 isNaN.. 10

4.2 isFinite. 11

4.3 isInteger. 12

5.数学对象拓展... 12

6.对象拓展... 12

6.1字面量(let obj = {}) 12

6.2 is【Object.is(? ,? )】... 13

6.3 assign(用于复制对象) 14

7.数组拓展... 15

7.1 from方法:【Array.from(arrLike, fn)】... 15

7.2 of方法:【Array.of()】... 16

7.3查找数组(find、findIndex) 16

7.4数组内部复制(arr.copyWithin(pos, start, end))... 17

7.5迭代器... 18

7.5.1迭代器方法... 18

7.5.2for of循环... 19

8. 解构... 21

8.1结构含义:(解析聚合数据的结构)... 21

8.2对象解构(let { key1, key2, ..keys} = obj)... 21

8.3数组解构(let [item1, item2, ..tems] = arr)... 23

8.4解构总结... 24

9.函数拓展... 24

9.1默认参数... 24

9.2获取剩余参数... 25

9.3箭头函数(let demo=(? )=>{? })... 26

1.ES6

1.1ECMAScript发展历史:

ES1.0 => 1997???? ES2.0 => 1998

ES3.0 => 1999???? S4.0 => 2007

ES3.1 => 2008???? S5 => 2009

ES6 => 2015???????? ES2016(ES7) => 2016

ES2017 => 2017? ES2018 => 2018

由于ES每年新增的特性非常之多,所以开始以年为单位,定义其版本,从ES6开始,吸取了ES4失败的教训,没有强制浏览器实现这些语法,而是将这些语法编译成ES5 (ES3.1) 版本,这样浏览器就支持了。

所以,ES6受到各大浏览器厂商广泛的认可,并开始实现其语法,因此好的浏览器能够支持90%以上的语法了,所以很多语法可以直接用浏览器测试。

ES6 着眼于未来,是为企业级大型项目的开发而设计的。由于还有很多浏览

器. (IE6,7,8)没有实现ES6语法,所以我们要编译ES6,ES6支持面向对象编程方式(class, extends等关键字),但是又保留了弱类型语言,动态语言的特征。

1.2ES6简介

ECMA组织为了让制定的规范被编译成可被浏览器支持的版本,提供了babel编译库,ES每次发布版本,babel都会更新一个版本,在新版本中提供的功能,通过babel拓展来实现编译。

在nodejs端,在6.0版本之后,开始支持ES6,所以我们可以在后面的node学习中直接使用ES6了。

在浏览器端,为了兼容更多的浏览器。我们需要将ES6的代码,编译成浏览器支持的版本。

:当前的语法浏览器支持,因此可以用浏览器直接测试。

2.关键字

2.1 let关键字

用来定义块作用域变量

var定义函数级作用域变量的:

在函数内部定义的变量,外部无法访问,

在代码块(if, for)中定义的变量,外部可以访问

let定义块作用域变量的:

函数内部定义的变量,外部无法访问

在代码块(if, for)中定义的变量,外部仍然无法访问

用来定义块作用域变量的???????

2.2 let与var比较

1.作用域

var函数级作用域?????????????????? let块级作用域

?//?块级作用域

????????if?(true)?{var?c?=?30;let?d?=?40;

????????????//?d?只能在代码块的内部访问

????????????console.log(d); ?}//40

????????console.log(c);//30

????????//?console.log(d);//let的外部无法访问

????????//因此,var是函数级的,let?是块级的

2.重复定义

var可以重复定义变量?????????? let不可以重复定义变量

??????//重复定义

????????var?color?=?'red';var?color?=?'green';

????????console.log(color);//green;

????????let?color2?=?'red';let?color2?=?'green';

????????console.log(color2);//报错//?has?already?been?declared

3.声明前置

var支持声明前置?????????????????? let不支持声明前置

//声明前置

????????console.log(ccc);//undefined//阔以访问,虽然无值

????????var?ccc?=?'RED';

????????let?ccc?=?'red';//报错//Cannot?access?'ccc'?before?initialization

4.for循环中存储数据

var不能存储数据?????????????????? let可以存储数据

?//利用闭包存储数据??

for?(var?i?=?0;?i?<?5;?i++)?{

????????????arr[i]?=?(function?(i)?{

????????????????return?function?()?{

????????????????????console.log(i);} })(i) }//立即执行

????????arr[3]()//3?//?arr[2]();//2

//利用let存储数据

????????for?(let?i?=?0;?i?<?5;?i++)?{?

????????????arr[i]?=?function?()?{

????????????????console.log(i);}}

arr[3]()//3

5.window挂载

var可以被挂载?????????????????????? let不能被挂载

???//?被window挂载

????????var?e?=?10;let?f?=?20;

????????console.log(window.e);//10

????????console.log(window.f);//undefined

2.2const关键字

const关键字是用于定义常量(一旦定义无法改变的变量,通常是表示一些固定不变的数据)

使用const关键字的特点:

1无法被修改

2支持块作用域

3无法重复定义

4无法声明前置

5不能被window挂载

6不能作为for循环体中的变量使用

7值只能是值类型如果是引用类型则可以被修改

工作中,通常是将用大写字母表示,并且横线分割单词,常用于定义配置量

在ES5中,我们可以通过冻结对象技术,或者设置writable:false特性,来模拟静态变量。但问题是:值如果是引用类型依然会被修改

在ES3.1中,我们可以通过单例模式来模拟静态变量。在方法中只定义取值方法,而不定义赋值方法即可

??//1.定义常量,不能修改

????????//?var?a?=?10;

????????//?a?=?20;

????????//?console.log(a);//20//阔以被修改

????????const?a?=?10;a?=?20;

????????console.log(a);//报错//Assignment?to?constant?variable.



????????//2.声明前置,不能前置,只能在后面访问

????????console.log(COLOR);const?COLOR?=?'red';

????????//报错//Cannot?access?'COLOR'?before?initialization



????????//3.不能重复定义

????????const?COLOR?=?'red';

????????const?COLOR?=?'asdas';//报错//'COLOR'?has?already?been?declared



????????//4.?块级作用域

????????function?demo()?{

????????????const?COLOR?=?'red';//支持函数级作用域

????????????//?var?COLOR?=?'red'

????????????//?let?COLOR?=?'red'

????????????console.log(111,?COLOR) };//111?"red"//外部都无法访问

????????demo();

????????//块级

????????if?(true)?{const?COLOR?=?'red';//支持块级作用域

????????????console.log(222,?COLOR);?}//222?"red"//外部无法访问

????????console.log(COLOR);?//外部都无法访问



????????//5.不能挂载在window

????????const?COLOR?=?'red';console.log(window.COLOR);//undefined



????????//6.不能作为循环变量(常量不能被改变)

????????for?(const?i?=?0;?i?<?5;?i++)?{

????????????console.log(i);

????????//第一次执行时,未被修改可以执行,第二次循环到i++时,修改了变量,报错

????????}



????????//7.值只能是值类型,不能是引用类型

????????const?OBJ?=?{width:?10,height:?20};

????????OBJ.width?=?111;OBJ.height?=?2222;

????????console.log(OBJ);//{width:?111,?height:?2222}

????????//会被修改,所以,不能使用引用类型



????????//8.ES5模拟

????????var?obj?=?{color:?'red',num:?98,

????????????size:?{//8.2

????????????????width:?100,height:?200}}

????????//8.1:设置特性

????????Object.defineProperties(obj,?{

????????????color:?{writable:?false},num:?{writable:?false},

????????????size:?{writable:?false},})

????????obj.color?=?'sdsd';obj.num?=?678;

????????obj.size?=?[1,?2,?3]//8.3没有修改size:{width:?123,?height:?200}

????????obj.size.width?=?123;?//8.2被修改了size:{width:?123,?height:?200}

????????//8.4即,size属性不能被修改,但是size的子属性可以被修改

????????console.log(obj);//8.1没有被修改{color:?"red",?num:?98}



????????//9.1:通过ES5中,对象的冻结实现

????????Object.freeze(obj);

????????obj.color?=?'sdsd';obj.num?=?678; //red //98

????????obj.size?=?[1,?2,?3];//没有修改size

????????obj.size.width?=?123;//可以修改:{width:?123,?height:?200}

??????console.log(obj);//color:?"red"?num:?98?{width:?123,?height:?200}

????????//同8.4:即,size属性不能被修改,但是size的子属性可以被修改

//10.1在ES3.1中,使用单例模式

????????var?conf?=?(function?()?{

????????????var?_data?=?{

????????????????color:?'red',num:?98,

????????????????size:?{width:?100,height:?200}}

????????????//只返回取值器,不返回复制器

????????????return?function?(key)?{return?_data[key];}

????????console.log(conf('color'));//red

????????console.log(conf('num'));//98

????????//如果返回的是对象可以被修改

????????conf('size').width?=?333333;

????????console.log(conf('size'));//{width:?333333,?height:?200}

3.字符串拓展

3.1多行字符串

3.1.1单行字符串:

一组单引号或者双引号定义的字符串

单行字符串的问题:

1单行字符串不能换行

2 一些特殊的按键要使用转义字符\n

3一些特殊的字符要使用转义字符\x20

4字符串标志符号不能直接嵌套

5单引号中不能直接写单引号,要转义\'

6双引号中不能直接写双引号,要转义\”

....

3.1.2多行字符串

ES6为了解决单行字符串中的问题,提供了多行字符串,

通过 ` 定义,在多行字符串中,只有`需要转义\,其他的字符,都可以直接书写

????????var?str?=?`hello

????????qaq???"?"?'?'??\`

????????`

????????console.log(str);

并且ES6多行字符串支持插值语法:

?${key}

${}提供了js环境,因此我们可以写js表达式

ES6的插值语法,让其它框架的插值语法的重要性,大打折扣。

????//数据

????????let?size?=?{width:?10,height:?20};

????????//?输出:面积:10x20=200

????????var?str?=?'面积:'?+?size.width?+?'x'?+?size.height?+?'='?+?size.height?*?size.width

????????//2.多行字符串

????????var?str?=?`面积:${size.width}x${size.height}=${size.width?*?size.height}`

????????console.log(str);//面积:10x20=200

例二:

???????//数据

????????let?data?=?[

{title:?'1.被枚举到(for...in?或?Object.keys?方法),',type:?'推荐'},

{title:?'2.可以改变这些属性的值,也可以删除这些属性。',type:?'关注'},

{title:?'3.这个方法允许修改默认的额外选项(或配置)。',type:?'热议'},

{title:?'4.默认情况下,使用?Object.defineProperty()',type:?'热点'},]

????????//定义字符串

????????let?html?=?'';

????????for?(let?i?=?0;?i?<?data.length;?i++)?{?//遍历数据

????????????//字符串拼接

????????????html?+=?`

????????????<li>

????????????????<span>${data[i].title}</span>

????????????????<span>${data[i].type}</span>

????????????</li>

????????????`}

??????????app.innerHTML?=?html;//?console.log(html);

3.2原始字符串(String.raw)

在使用了转义字符之后,并且在浏览器查看的时候,我们只能看到结果不能看到原始完整的字符串(包含转义字符),于是ES6中拓展了String.raw方法。

用于,查看完整的原始字符串。

使用方式:

String.raw``

1.参数通过多行字符串的形式传递

2.字符串中的转义字符串不会被转义

//转义字符

????????let?str?=?`hello?\nqa\nq`;//被转义了,即换行了

????????//原始字符串

????????//?let?str?=?String.raw`hello?\nqa\nq`//hello?\nqa\nq

????????console.log(str);

????????//实现://不让\n实现,把\n改成\\n即可

????????//注意\\n是一个整体,匹配修改时,要一起匹配

????????console.log(str.replace(/\n/g,?'\\n'));//hello?\nqa\nq

3.3重复字符串(repeat)

ES6中拓展了repeat方法用于重复输出字符串

参数:要重复的次数

返回值:重复的结果

注意:不影响原始字符串

????????let?str?=?`hello?||`;?//?重复字符串(repeat)

????????//让str重复三次

????????console.log(str.repeat(3));//hello?||hello?||hello?||

????????console.log(str.repeat(0));//

????????console.log(str);//hello?||

????????//实现:

????????String.prototype.qaqRepeat?=?function?(num)?{

????????????var?result?=?''; //this?代表字符串//定义结果字符串

????????????//循环拼接

????????????for?(var?i?=?0;?i?<?num;?i++)?{result?+=?this;}

????????????return?result}

????????console.log(str.qaqRepeat(3));//hello?||hello?||hello?||

3.4判断字符串位置

startsWith(str, pos)

是否以参数字符串开头

截取后面的部分,并且包含截取位置字符

str:参数字符串 (子字符串)???????????? pos:字符串截取位置

返回值:布尔值

??//定义字符串

????????//????????0?1?2?3?4?5?6

????????let?str?=?`我是一个大帅逼`

?console.log(str.startsWith('我',?0));//true

????????console.log(str.startsWith('帅逼',?5));//true

endsWith(str, pos)

是否以参数字符串结尾

截取前面的部分,并且不包含截取位置字符

?console.log(str.endsWith('帅逼'));//true

????????console.log(str.endsWith('帅',?5));//false

????????console.log(str.endsWith('帅',?6));//true

includes(str, pos)

是否包含参数字符串

截取后面的部分,并且包含截取位置字符

????console.log(333,?str.includes('帅'));//true

????????console.log(333,?str.includes('帅逼',?5));//true

4.数字拓展

ES6中为数字拓展了几个方法:

?isNaN(数字?) isFinite(有限?) isInteger(整数?)

????? ??var?num1?=?0?/?1;//??????0

????????var?num2?=?0?/?-?1;//???-0

????????var?num3?=?1?/?0;//?????Infinity

????????var?num4?=?-?1?/?0;//???-Infinity

????????var?num5?=?0?/?0;//?????NaN

4.1 isNaN

1.全局中的NaN

全局中有一个isNaN方法,是用于判断是否是NaN(not a Number)

全局中isNaN在判断的时候,会进行类型转换

???????console.log(isNaN(num4));???????//F

????????console.log(isNaN(num5));???????//T

????????console.log(isNaN(100.00));?????//F

????????console.log(isNaN('100abc'));???//T

????????console.log("+'100abc'",?isNaN(+'100abc'));??//F//T//存疑

????????//用typeof查看+'100abc?时,貌似会会在后台进行数字的?转换

????????console.log(isNaN(parseInt('100abc')));??//F

//?isNaN('123ABC');

//?👆true:??parseInt("123ABC")的结果是?123,?但是Number("123ABC")结果是?NaN

????????console.log(isNaN(Math.floor('100abc')));?//F//T

????????//Math方法不支持隐性转换,100abc仍是字符串?不是一个数字

????????console.log(isNaN(1?/?3));?//F

????????console.log(isNaN(Math.PI));?//F

2.Number拓展的isNaN

在判断的时候不会做类型转换

1.先必须是数字

其次才去判断是否是NaN

2.如果NaN,则返回true

如果不是NaN,则返回false

??????? console.log(Number.isNaN(num4));???????????????????//F

????????console.log(Number.isNaN(num5));???????????????????//T

????????console.log(Number.isNaN(100.00));?????????????????//F

????????console.log(Number.isNaN('100abc'));//T//先直接判断类型:字符串//F

console.log(Number.isNaN(+'100abc'));//T//是数字类型,但不是一个数字//是NaN

????????console.log(Number.isNaN(parseInt('100abc')));?????//F

????????console.log(Number.isNaN(Math.floor('100abc')));???//T

????????console.log(Number.isNaN(1?/?3));??????????????????//F

????????console.log(Number.isNaN(Math.PI));????????????????//F

4.2 isFinite

全局中:

有一个isFinite方法, 是用于判断是否是有限的

全局中的isFinite,在判断的时候,会进行类型转换

Number拓展的isFinite

在判断的时候不会做类型转换

1.首先必须是数字

其次才去判断是否是有限的

2.如果是有限的,则返回true

如果不是有限的,则返回false

注意:

?????? 1. 判断数学上是不是有限的

?????? 2. 只要是整数都是有限的

?console.log(Number.isFinite(num4));???????????????????//?T?//F

????????console.log(Number.isFinite(num5));???????????????????//?F

????????console.log(Number.isFinite(100.00));?????????????????//?F?//T

????????console.log(Number.isFinite('100.00'));???????????????//?F

????????console.log(Number.isFinite('100abc'));???????????????//?F

????????console.log(Number.isFinite(+'100abc'));??????????????//?F

????????console.log(Number.isFinite(parseInt('100abc')));?????//?F?//T

????????console.log(Number.isFinite(Math.floor('100abc')));???//?F

????????console.log(Number.isFinite(1?/?3));??????????????????//?F?//T

????????console.log(Number.isFinite(Math.PI));????????????????//?F?//T

4.3 isInteger

Number拓展的isInteger方法,用于判断是否是整型的

在判断的过程中,会校验类型

1.首先必须是数字

其次才去判断是否是整型的

2.如果是整型,则返回true

如果不是整型,则返回false

5.数学对象拓展

就是Math对象的拓展

ES6为了适应大型项目,解决自身运算的问题,拓展了大量的方法。

Math.cbrt:计算一个数的立方根

Math.fround:返回一个数的单精度浮点数形式。

Math.hypot:返回所有参数的平方和的平方根

Math.expm1(x):返回ex- 1。

Math.log1p(x):返回1 + x的自然对数。如果x小于-1,返回NaN。

Math.log10(x):返回以10为底的x的对数。如果x小于0,则返回NaN。

Math.log2(x):返回以2为底的x的对数。如果x小于0,则返回NaN。

三角函数方法:

Math.sinh(x)返回x的双曲正弦(hyperbolic sine)

Math.cosh(x)返回x的双曲余弦(hyperbolic cosine)

Math.tanh(x)返回x的双曲正切(hyperbolic tangent)

Math.asinh(x)返回x的反双曲正弦(inverse hyperbolic sine)

Math.acosh(x)返回x的反双曲余弦(inverse hyperbolic cosine)

Math.atanh(x)返回x的反双曲正切(inverse hyperbolic tangent)

Math.sign返回一个数字的标志,用来判断数字范围的

(0, Infinity] =>1,[-Infinity, 0) => -1,0=>0,-0 => -0,NaN =>NaN

6.对象拓展

6.1字面量(let obj = {})

对象字面量: letobj = {}

省略语法:

1如果定义的属性名称属性值变量同名,我们可以省略属性名称以及冒号

2可以对属性名称书写表达式,通过[]动态的设置属性名称,之前可以通过[]获取属性,现在我们可以通过[]设置属性名

3在对象中定义的方法可以省略冒号以及function关键字

???????? let?color?=?"red";

????????let?obj?=?{//定义对象

????????????//?color:?color//1.1添加一个color属性

????????????//1.2如果定义的属性名称与属性值变量同名,可以省略属性名称以及冒号

????????????color,

????????????//1.4对象字面量中,可以通过[]来动态的设置属性名称

????????????[color]:?200,

????????????//1.5?[?]提供了js环境,可以书写复杂的表达式

????????????[color.toLocaleUpperCase()?+?'hello']:?200,

????????????//1.6获取方法

????????????//?getColor:?function?()?{??//老式写法

????????????//?????return?this.color; }

??????????//ES6中,属性方法可以省略冒号以及function关键字

????????????getColor()?{return?this.color;}};

????????//设置属性

????????//?obj[color]?=?100;//1.3{color:?"red",?red:?100}

????????console.log(obj);

????????//1.1&1.2{color:?"red"}

????????//1.4{color:?"red",?red:?200}

????????//1.5{color:?"red",?red:?200,?REDhello:?200}

????????//1.6{color:?"red",?red:?200,?REDhello:?200,?getColor:??}

????????console.log(obj.getColor());//1.6//red

6.2?is【Object.is( ?, ?)】

is方法用于判断两个参数是否全等(===)

全等判断有几个问题:

1:0和 -0之前在进行全等判断的时候,得到的是true

0和- 0之间是差了一个符号位在二进制中,存储的数据是不同的

2:NaNNaN在进行全等判断的时候,得到的是false

3:所有NaN都表示“不是一个数字”,它们存储的地址是一样

对象拓展的is方法:

在判断0-0的时候得到的false

在判断NaN的时候得到的就是true

注意:

?????? 比较的是存储的地址。

????? ? ?console.log(0?/?1?===?0?/?-1);??????? ?//true

????????console.log(NaN?===?+'asd');???????????//false

????????//is方法纠正上述?===?的错误//除此之外,is方法与?===?是一致的

????????console.log(Object.is(0?/?1,?0?/?-1));?//false

????????console.log(Object.is(NaN,?+'asd'));???//true

6.3 assign(用于复制对象)

ES6拓展的assign是用于复制对象的,和jQuery、undescore中的extend方法类似

使用方式: Object.assign(obj, obj1, obj2)

obj:被复制的目标对象

第二个参数开始,都是复制的对象

返回值:目标对象obj

注意:

1.后面对象中的同名属性会覆盖前面对象中的属性

2.assign方法实现的是一个浅复制

浅复制:

值类型是直接复制,而引用类型是改变指向,没有真正的复制

深复制:

值类型是直接复制,引用类型也是直接复制,并不是改变指向(函数除外)

3.简单实现深复制: JSON.parse(JSON.stringify), 但是转换json字符串的时候,会过滤掉函数

4.jQuery中的extend方法,第一个参数传递 true的时候就是深复制

?//实现(浅复制)(这是静态方法,直接放在Object上面)

????????Object.qaqAssign?=?function?(target)?{

????????????//遍历后面的参数对象

????????????for?(var?i?=?1;?i?<?arguments.length;?i++)?{

????????????????//获取当前参数对象

????????????????var?obj?=?arguments[i];

????????????????//将obj中的属性赋值给target

????????????????for?(var?key?in?obj)?{

????????????????????target[key]?=?obj[key]; ? //赋值

                }

            }

????????????//返回目标对象

????????????return?target}

????????var?result?=?Object.qaqAssign(obj1,?obj2,?obj3);

7.数组拓展

7.1 from方法:【Array.from(arrLike, fn)】

from方法是用于遍历类数组对象,或将类数组对象转换成数组,是数组的静态方法。

类数组对象:

1.可以通过索引值获取属性值,并且要具备length属性的这一类对象

2.类数组对象不能使用数组的遍历器方法,ES6中拓展的from方法可以将类数组对象转为真正的数组,之后就可以使用数组的常用方法

使用方式:

Array.from(arrLike, fn)

arrLike:类数组对象

fn:执行的函数

参数:??????????? 成员值、索引值

作用域: ??全局作用域(即this默认指向window)

如果传递的fn参数,此时,fn方法的返回值是from函数的执行结果

总结:

from方法不仅可以将类数组转为数组,还可以遍历类数组对象

????<div>1-1-1</div>

????<div>2-2-2</div>

????<div>3-3-3</div>

????<div>4-4-4</div>

????<div>5-5-5</div>

?//将类数组对象转成数组

????????//1.可以将类数组转为数组;2.还可以遍历类数组对象

????????let?arr?=?Array.from(div,?function?(item,?index)?{

????????????console.log(111,?arguments);

????????????//3.返回值影响from方法运行的结果

????????????return?index});

????????console.log(arr);//(5)?[div,?div,?div,?div,?div]

????????arr.forEach(function?()?{

????????????console.log(arguments);})

//实现

????????Array.qaqFrom?=?function?(arrLike,?fn)?{

????????????//1.定义返回的数组

????????????let?result?=?[];

????????????//2.遍历类数组对象

????????????for?(var?i?=?0,?len?=?arrLike.length;?i?<?len;?i++)?{

????????????????//2.1判断是否传递fn

????????????????if?(fn)?{

????????????????????//2.2传递了fn,存储fn执行结果

????????????????????result.push(fn(arrLike[i],?[i]))

????????????????}?else?{

????????????????????//2.3没有传递fn,直接存储fn的成员

????????????????????result.push(arrLike[i],?[i])}}

????????????return?result;}

????????//使用

????????var?arr?=?Array.qaqFrom(div,?function?(item,?index)?{

????????????item.innerHTML?=?'qaq'?+?index;

????????????return?item;});

????????console.log(arr);

7.2 of方法:【Array.of()】

of方法用于创建数组的,是数组的一个静态方法

之前通过new Array(或者是Array()创建数组有一些问题:

? 1如果没有传递参数,得到的是一个空数组

? 2如果传递了一个数字参数,得到的是带有一个长度的空数组

? 3如果传递一个非数字参数,得到的是带有一个成员的数组

? 4如果传递了多个参数,得到就是一个带有多个参数的数组

ES6中拓展的of方法可以实现:将所有传递的参数都作为数组中的成员存在

创建数组的四种方式

字面量[],

构造函数new Array(),

工厂方法Array(),

Array.of()

?//实现数组的静态方法,

????????Array.qaqOf?=?function?()?{

????????????//?console.log(arguments);

????????????//?return?Array.from(arguments)//一:ES6方法

????????????//二:普通方法:slice方法可以转换数组

????????????return?Array.prototype.slice.call(arguments)}

????????let?arr1?=?Array.qaqOf();?????????//[]

????????let?arr2?=?Array.qaqOf(5);????????//[5]

????????let?arr3?=?Array.qaqOf('5');??????//["5"]

????????let?arr4?=?Array.qaqOf(5,?6,?7);??//[5,?6,?7]

????????console.log(arr1,?arr2,?arr3,?arr4);

7.3查找数组(find、findIndex)

在ES5中拓展了查找成员的方法: indexOf lastIndexOf

在ES6中拓展了查找成员的方式:?find findIndex

1.允许参数是可以执行的函数

2.参数:执行的函数

函数中有三个参数:成员值、索引值、原数组

3.作用域:全局作用域(即this默认指向window

4.find方法

在查找成员的时候,如果找到了则返回该成员,如果没有找到则返回undefined

5.findIndex方法

在查找成员的时候,如果找到了则返回该成员的索引值,如果没有找到返回-1,在查找的过程中,一旦找到则停止遍历

7.4数组内部复制(arr.copyWithin(pos, start, end))

ES6为了实现数组内部复制成员提供了一个方法: copyWithin

1.使用方式:

arr.copyWithin(pos, start, end)

pos: ?要粘贴的位置

start: 要复制的起始位置(包含起始位置)

end: ?要复制的结束位置(不包含结束位置)

返回值:原数组,并且原数组发生变化

例如:

[0,1,2,3,4,5, 6,7,8,9]. copyWithin(3, 6, 9)

结果:

[0,1,2,6,7,8,6,7,8,9]

???????????? //实现

????????Array.prototype.qaqCopyWithin?=?function?(pos,?start,?end)?{

????????????//截取

????????????var?arr?=?this.slice(start,?end);

????????????//?for?(var?i?=?0;?i?<?arr.length;?i++)?{//法一:粘贴

????????????//?????//更新成员,返回原数组

????????????//?????this[i?+?pos]?=?arr[i];

????????????//?}



????????????//法二:数组操作

????????????//?(splice()?方法用于添加或删除数组中的元素。)

????????????//?array.splice(index,howmany,item1,.....,itemX)

????????????//?this.splice(pos,?end?-?start)

????????????//?this.slice.apply()将数组作为参数传递

????????????this.slice.apply(this,?[pos,?end?-?start].concat(arr))

????????????//返回原数组

????????????return?this;}

????????//缩成一句话

????????Array.prototype.qaqCopyWithin?=?function?(pos,?start,?end)?{

return?this.slice.apply(this,?[pos,?end?-?start].concat(this.slice(start,?end))),?this;}

????????//逗号语法,前面的执行完后,执行后面的,并把后面的作为return返回

????????var?result?=?arr.qaqCopyWithin(2,?5,?8);

????????console.log(result);//[0,?1,?5,?6,?7,?5,?6,?7,?8,?9]

????????console.log(result?===?arr);//true//修改的是原数组

7.5迭代器

7.5.1迭代器方法

ES6中为了遍历数组中成员,拓展了三个迭代器方法:

keysvaluesentries

keys:获取索引值

values:获取成员值

entries:获取索引值以及成员值: [index, item, ]

由于实现了数组的迭代器接口方法,就可以使用for of或者是next方法遍历

实现了迭代器接口的数据,都有next方法,可以通过next方法来遍历成员

返回值:一个对象

value:表示成员值

done:表示是否遍历完成

如果遍历完成了,此时: done将永远是true

value将永远是undefined

var?arr?=?['red',?'green',?'blue',?'pink'];

????????//?//创建迭代器//索引值

????????//?var?result1?=?arr.keys();

????????//?console.log(result1);



????????//还可以通过for?of循环遍历

????????var?result1?=?arr.values();

????????for?(let?item?of?result1)?{

????????????console.log(item);

}

????????//遍历每一个成员

????????console.log(result1.next());//{value:?0,?done:?false}

????????console.log(result1.next());//{value:?1,?done:?false}

????????console.log(result1.next());//{value:?2,?done:?false}

????????console.log(result1.next());//{value:?3,?done:?false}

????????console.log(result1.next());//{value:?undefined,?done:?true}

????????console.log(result1.next());//{value:?undefined,?done:?true}



????????//创建迭代器//成员值

????????var?result2?=?arr.values();

????????console.log(result2);

????????//遍历每一个成员

????????console.log(result2.next());//{value:?red,?done:?false}

????????console.log(result2.next());//{value:?green,?done:?false}

????????console.log(result2.next());//{value:?blue,?done:?false}

????????console.log(result2.next());//{value:?pink,?done:?false}

????????console.log(result2.next());//{value:?undefined,?done:?true}

????????console.log(result2.next());//{value:?undefined,?done:?true}



????????//创建迭代器//成员值

????????var?result3?=?arr.entries();

????????console.log(result3);

????????//遍历每一个成员

????????console.log(result3.next());//{value:?Array(2),?done:?false}//value:?(2)?[0,?"red"]

????????console.log(result3.next());//

????????console.log(result3.next());//

????????console.log(result3.next());//

????????console.log(result3.next());//



//一旦遍历完成,需要重新创建一个迭代器,var?result4=.......

7.5.2for of循环

1.for of循环是ES6专门为实现了迭代器接口的对象设计的循环结构

for of是专门为迭代器接口设置的遍历方法

2.语法:

for (let item of data) {}

可以像其它循环一样在内部使用continue break等关键字

3.for of也是可以遍历数组的,但是在遍历过程中无法使用索引值

遍历数组的时候,item表示数组的每一个成员,没有办法访问索引值,但是我们可以在外部定义一个循环变量,在循环体中手动更新。

for of循环遍历数组的时候,不需要通过索引值访问成员,而for循环以及for in循环要通过索引值访问

4.for in也可以遍历数组,但是有一些问题:

遍历的时候,key显示的是字符串,不是数字(改变了索引值类型)

5.总结:

for循环用于遍历数组、类数组对象

for in循环用于遍历对象

for of循环遍历实现了迭代器接口的对象(包括数组)

????? ??var?arr?=?['red',?'green',?'blue',?'pink'];

????????//创建迭代器//索引值

????????var?result1?=?arr.values();

????????//for循环与?for?in循环无法遍历

????????//?for?(var?i?=?0;?i?<?result1.length;?i++)?{

????????//?????console.log(result1);//没有报错,但是也没有执行

????????//?}

????????for?(let?key?in?result1)?{

????????????console.log(key); ?}//没有报错,但是也没有执行



????????//循环//遍历对象

????????for?(let?item?of?result1)?{

????????????//?//遍历到蓝色就停止

????????????//?if?(item?===?'blue')?{

????????????//?????break;

????????????//?}

????????????//?//遍历到蓝色就跳过蓝色

????????????//?if?(item?===?'blue')?{

????????????//?????continue;

????????????//?}

????????????console.log(item);}

????????//迭代器对象一旦遍历完成,就无法再遍历了

????????for?(let?ltem?of?result1)?{

console.log(222); }//前面迭代器执行过result1之后,就不会再执行这个循环了

????????

????????//遍历数组

????????for?(let?item?of?arr)?{console.log(item);}

????????for?(let?item?of?arr)?{console.log(222,?arr);}

????????//数组可以多次遍历



????????//?for?of也是可以遍历数组的,但是在遍历过程中,无法使用索引值

????????var?index?=?0;

????????for?(var?item?of?arr)?{

????????????console.log(item,?index);

????????????//与while循环类式,需要手动更新循环变量

????????????index++;}

8.?解构

8.1结构含义:(解析聚合数据的结构)

1.所谓解构就是解析聚合数据的结构

2.在ES5中的聚合数据有:

对象、数组

在之前,对象中获取数据的方式

只能通过点语法或中括号语法

在之前,数组中获取数据的方式

只能通过中括号语法

3.在ES6中简化了获取数据的方式,提供了解构语法:对象解构与数组解构

4.解构语法不会影响原来的数据

8.2对象解构(let { key1, key2, ..keys} = obj)

1.语法:

let { key1, key2, ..keys} = obj;?

key1相当于obj.key1

key2相当于obj.key2

keys获取的是剩余的属性,如果没有剩余的属性,获取到的就是一个空对象

注意:

解构出来的属性、变量一定是和对象中的属性同名

??????? ?var?obj?=?{

????????????num:?100,color:?'red',shuaibi:?'it?is?me',

????????????arr:?[1,?2,?3],

????????????size:?{width:?222,height:?555},

????????????demo()?{

????????????????console.log(222,?this); }};//指向调用者:obj

????????//过去访问数据?的方法:通过访问obj获取数据

????????//?console.log(obj.num);//100

????????//?console.log(obj['color']);//red



????????//ES6对象解构语法:?let?{?key1,?key2,?..keys}?=?obj;

????????//其中:?...keys三点语法获取剩余的属性

????????//?let?{?num,?color,?...qaq?}?=?obj;

????????console.log(num);//100

????????console.log(color);//red

????????console.log(qaq);//{}//没有剩余的对象就为:空对象

????????//{shuaibi:?"it?is?me",?arr:?Array(3),?size:?{…},?demo:??}

????????obj.demo()

2.解构问题:

1如果使用var解构,会污染全局对象(window),我们可以使用let关键字解决

//使用var会污染全局对象,一般使用let

????????var?{?num,?color,?...qaq?}?=?obj;

????????console.log(window.num);//100

????????//结构语法相当于在全局?var?num?=?obj.num;//var?换成let即可

2解构出来的方法,方法中的this将发生变化

?????? ?obj.demo();//指向调用者:obj

????????//结构出来,this指向会发生改变

????????let?{?num,?color,?demo,?...qaq?}?=?obj;

????????demo();

????????//指向为window//因为相当于let?demo=?obj.demo,window也调用了demo

????????//Window?{window:?Window,?self:?Window,?document:?document,?name:?"",?location:?Location,?…}

????????//注意:严格模式指向undefined

3对于引用类型来说,只是指向的改变,而对于值类型来说,是真正的复制

??//结构值类型的是复制,结构引用类型的是指向改变(引用同一个)

????????let?{?num,?color,?demo,?arr,?size,?...qaq?}?=?obj;

????????//修改数据

????????num?=?200; arr[1]?=?112233; size.width?=?123;

????????console.log(num);//200

????????console.log(arr);//[1,?112233,?3]

????????console.log(size);//{width:?123,?height:?555}

????????console.log(obj);

????????/**?arr:?(3)?[1,?112233,?3]?//引用类型?:指向同一个存储地址

?????????*?color:?"red"???????????//值类型:是直接复制一份,改变前后互不影响

?????????*?demo:???demo()

?????????*?num:?100

?????????*?shuaibi:?"it?is?me"

?????????*?size:?{width:?123,?height:?555}**/

3.逆运用:

我们可以通过三个点语法,将一个对象中的所有数据传递给一个对象字面量中: { ...keys }

?//?结构语法的:逆运用:

????????let?{?num,?color,?demo,?...qaq?}?=?obj;

????????//?注意:num和color是对象字面量的省略语法

????????//??????(对象与属性名同名[参./ES06-01/04.1],...qaq是解构的逆运用)//记住等号是赋值的意思即可

????????var?newObj?=?{?num,?...qaq?};

????????console.log(newObj);

????????//{num:?100,?shuaibi:?"it?is?me",?arr:?Array(3),?size:?{…}}

????????//注意:由于解构出来的数据会创建全局变量,因此,工作中常配合模块化开发使用(相当于局部变量)

8.3数组解构(let [item1, item2, ..tems] = arr)

1.语法:

let [item1, item2, ...items] = arr;

item1表示第一个成员

item2表示第二个成员

items表示剩余的成员

注意:

1.如果使用var解构,也会污染全局对象(window) ,我们可以通过使用let关键字解决

2.左边数组与数据有对应的成员,返回成员;没有的话,返回undefined

???????var?arr?=?['red',?'green',?'blue',?'pink',

                 ?'orange',?'gold',?'yellow',?'purple',?'gray'];

????????//?console.log(arr.slice(2));//获取第三个及其后面的成员

????????//结构语法//let?[item1,?item2,?..tems]?=?arr

????????//注意:var?同样会污染window,使用let即可

????????//等价方式:?let?red?=?arr[0];

????????let?[red,?green,?...items]?=?arr;

????????console.log(red,?green);//red?green

????????console.log(items);//?["blue",?"pink",?"orange",?"gold",?"yellow",?"purple",?"gray"]

2.获取剩余成员的语法:

1如果数组有剩余的成员,获取到的是数组中所有的剩余成员

2如果没有剩余的成员,获取到的是一个空数组

3前面解构的变量,可以正常使用

3.逆运:

我们可以通过三个点语法,将一个数组中的所有数据传递到一个数组字面量中[ ...r](复制数组)

????????//解构

????????let?[red,?green,?...items]?=?arr;

????????//复制数组

????????//?var?newArr?=?[red,?green,?...items];

????????var?newArr?=?[red,?...items,?green];//注意,新数组里面的顺序,是按复制的顺序排列

????????console.log(newArr);//["red",?"green"......]全部都复制了过来

?//如果只传递?...items,newArr与arr成员完全相同,但不相等

????????var?newArr?=?[...items];

????????console.log(newArr?==?arr);//false

????????console.log(newArr?===?arr);//false

8.4解构总结

1.记住单个等号赋值的意思即可:

解构指的是等号左侧的部分,

逆运用是等号右侧的部分,

例如,复制数据

2.解构:

对象解构,属性名称匹配

数组解构,索引值匹配(位置对应)

9.函数拓展

9.1默认参数

之前适配默认参数的方式:

1可以通过 || 运算符来适配参数的默认值

但是使用 || 运算符会忽略6个值为false的参数:

?0 ‘ ’ undefined null false NaN

2可以使用三元运算符: ?

? ?: ??

如果参数过多,书写比较麻烦

3使用extend | assign方法适配对象, 对于值类型的参数不适用

4 在ES6为了解决这样的问题,提供了适配默认参数的方式,直接在参数集合中为形参赋值即可

如果传递了参数,则使用传递的参数

如果没有传递参数,则使用默认参数

注:ES6拓展的适配默认参数的方式与三元运算符的方式是等价的

????? ??//定义函数

????????//4.1在ES6中,可以直接为参数赋值,定义默认参数

????????function?demo(color?=?'pink')?{

????????????//1.1通过?||(或)运算符设置默认值

????????????//?color?=?color?||?'red';

????????????//2.1三元运算符适配,如果参数较多会比较麻烦

????????????//?color?=?color?===?undefined???'red'?:?color;

????????????//3.使用extend?|?assign方法适配对象,?对于值类型的参数不适用。且是比较麻烦的

????????????console.log(color);

????????}

????????//执行函数并传递参数

????????demo();?????????//1.2?red???//2.1?red???//4.1?pink

????????demo(0);????????//1.2?red???//2.1??0????//4.1??0

????????demo(NaN);??????//1.2?red???//2.1?NaN???//4.1?NaN

????????demo(false);????//1.2?red???//2.1?false?//4.1?false

????????demo(null);?????//1.2?red???//2.1?null??//4.1?null

????????demo(undefined);//1.2?red???//2.1?red???//4.1?pink

????????demo('red');????//1.2?red???//2.1?red???//4.1?red

9.2获取剩余参数

之前,可以通过arguments来获取所有参数,但是arguments是一个类数组对象,不能使用数组的常用方法。

于是ES6拓展了获取剩余参数语法获取的剩余参数是一个数组,所以可以直接使用数组的常用方法

1.语法:

function demo(arg1, arg2, ...args) {}

arg1表示第一个参数

arg2表示第二个参数

args表示剩余的参数

????????//?function?demo()?{

?????//?console.log(arguments); }//1.1类数组,不能直接使用数组方法

//?获取剩余参数

????//?function?demo(num1,?num2,?...args)?{

//console.log(num1,?num2,?...args); }//2.1获取的是数组,可以使用数组方法

?? ??????demo();??????????????//1.2:[]???????//2.2:undefined?undefined

????????demo(1);?????????????//1.2:[1]?????????//2.2:1?undefined

????????demo(1,?2);??????????//1.2:[1,2]???????//2.2:1?2

????????demo(1,?2,?3);???????//1.2:[1,2,3]?????//2.2:1?2?3

????????demo(1,?2,?3,?4);????//1.2:[1,2,3,4]???//2.2:1?2?3?4

????????demo(1,?2,?3,?4,?5);?//1.2:[1,2,3,4,5]?//2.2:1?2?3?4?5

//3.1求参数和老方法

????????function?add()?{

????????????//?根据argument求和

????????????var?result?=?0;

????????????for?(var?i?=?0;?i?<?arguments.length;?i++)?{

????????????????result?+=?arguments[i]}

????????????return?result}

????????console.log(add(1,?2,?3,?4,?5)); //3.2测试//15

????????//3.3获取剩余参数?求和

????????function?add(...nums)?{//通过数组的方法求和

????????????return?nums.reduce(function?(res,?item)?{

????????????????return?res?+?item},?0)}

????????console.log(add(1,?2,?3,?4,?5));//15

2.获取剩余参数的语法:

1如果有剩余的参数,获取到的是一个由所有剩余参数组成的数组

2如果没有剩余的参数,获取到的是一个空数组

3前面参数可以正常使用,如果没有对应的参数,返回undefined

4在箭头函数中有广泛的应用

3.获取剩余参数的逆运用:

语法:

demo(...args)

1.我们可以将一个数组中成员作为参数传递到一个方法中

2.在之前我们可以通过apply方法,将数组中的每一项数据传递到一个方法中

3.但是使用apply需要考虑this的指向问题

4.我们可以使用获取剩余参数的语法,就不需要考虑this指向的问题了,正常执行函数。

??//4.1逆运用

????????var?arr?=?[1,?2,?3,?4,?5];

????????function?add(...nums)?{

????????????//通过数组的方法求和

????????????return?nums.reduce(function?(res,?item)?{

????????????????return?res?+?item

????????????},?0)

}

????????//?//4.2使用apply传递

????????//?var?result?=?add.apply(null,?arr);

????????//4.3使用?...args传递

????????let?result?=?add(...arr)

????????console.log(result);//4.2/4.3:?15

9.3箭头函数(let demo=(? )=>{? })

1.在ES5中定义函数的方式:

?1函数定义式、 2函数表达式、 3构造函数式

4.在ES6中又拓展了一种方式:

箭头函数

2.语法:

let demo=(? )=>{? }

(? ) : ?表示参数集合

=> :? 是箭头函数的标志

{? } :? 是函数体

3.几点省略语法:

1如果参数集合中只有一个参数,即可省略参数集合

如果使用三个点语法获取剩余参数或者解构语法不能省略参数集合

2如果函数中只有一句话,或者只有返回值的时候,可以省略return以及函数体

??????? //?4.1省略参数集合

????????let?print?=?(msg)?=>?{

????????????console.log(msg);}

????????//4.3只有一个参数省略参数集合

????????let?print?=?msg?=>?{

????????????console.log(msg);}

????????print('hello');//4.2/4.3?hello

????????//4.4获取剩余参数语法不能省略

????????let?print?=?(...args)?=>?{

????????????console.log(...args); }//三个点语法的逆运用

????????print(100,?'hello',?true);//4.5?100?"hello"?true

????????//4.6解构语法不能省略

????????let?print?=?({?msg?})?=>?{

????????????console.log(msg);}

????????print({?color:?'red',?msg:?'hello'?})//hello



????????//4.7省略函数体

????????var?arr?=?[1,?3,?5,?7,?9];

????????//数组映射

????????//?let?result?=?arr.map((item)?=>?{

????????//?????//?return?item?*?item

????????//?????//?return?Math.pow(item,?2)

????????//?????return?Math.pow(item,?3)

????????//?})

????????//4.8进行省略

????????//?let?result?=?arr.map(item?=>?item?*?item)

????????let?result?=?arr.map(item?=>?Math.pow(item,?2))

????????console.log(result);//[1,?9,?25,?49,?81]

4. 箭头函数的特点:

1无法使用arguments,但是我们可以使用三个点语法获取剩余参数

????????//?//?1.1无法使用arguments

????????//?let?add?=?(...args)?=>?{//1.3添加...args

????????//?????//?console.log(args);//1.2//1.3

????????//?????return?args.reduce((res,?item)?=>?res?+?item)//1.5

????????//?}

????????//?console.log(add(1,?2,?3,?4,?5));

????????//1.2报错arguments不能使用 ?

?//1.3?[1,?2,?3] ??//1.5?15

????????//1.6简化

????????let?add?=?(...args)?=>?args.reduce((res,?item)?=>?res?+?item)

????????console.log(add(1,?2,?3,?4,?5));//1.6?15

2无法作为构造函数来使用

?//?2.1无法作为构造函数来使用

????????//?function?Player(x,?y)?{

????????//?????this.x?=?x;

????????//?????this.y?=?y;}

????????//?//2.7函数表达式

????????//?let?Player?=?function?(x,?y)?{

????????//?????this.x?=?x;

????????//?????this.y?=?y; }

????????//2.8箭头函数不允许

????????let?Player?=?(x,?y)?=>?{

????????????this.x?=?x;

????????????this.y?=?y;}

????????//?//2.2定义原型方法//老方法

????????//?Player.prototype={

????????//?????constructor:?}//这个需要重写

????????//?Player.prototype.getPosition?=?function?()?{?};//2.3

????????//2.4

????????Object.assign(Player.prototype,?{

????????????getPosition()?{

????????????????console.log(this.x,?this.y);}})

????????//2.5实例化

????????let?p?=?new?Player(100,?200);

????????p.getPosition()

????????//2.6/2.7?100?200

????????//2.8?报错:箭头函数不能作为构造函数

3箭头函数中的this指向永远是定义时

?????? A在普通函数中,this是执行时的上下文对象,谁调用指向谁

B无论使用call、apply或者是 bind方法都无法改变箭头函数的this指向

C改变箭头函数this指向唯一的方式就是改变其宿主环境this

也就是说改变其外部函数的作用域

??????? ?//3.1箭头函数中的this指向永远是?定义时的

????????//3.2严格模式:中的普通函数?this是undefined

????????'use?strict'

????????console.log(this);//window

????????var?demo?=?()?=>?{

????????????console.log(this);

????????};

????????//3.3普通函数

????????function?demo2()?{

????????????console.log(this);

????????}

????????demo()//3.1?Window

????????demo2()//3.3?undefined

  JavaScript知识库 最新文章
ES6的相关知识点
react 函数式组件 & react其他一些总结
Vue基础超详细
前端JS也可以连点成线(Vue中运用 AntVG6)
Vue事件处理的基本使用
Vue后台项目的记录 (一)
前后端分离vue跨域,devServer配置proxy代理
TypeScript
初识vuex
vue项目安装包指令收集
上一篇文章      下一篇文章      查看所有文章
加:2021-10-21 12:06:15  更:2021-10-21 12:07:20 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/13 3:09:25-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码