ECMAScript6


前言

大概是半年前学的,当时放到CSDN上的,现在搬到自己博客上

这是我学习ES6的笔记,语言偏向口语化,主要是个人觉得这样会比较亲切…

由于是学习笔记,内容可能会有不够详实,存在瑕疵等诸多问题,欢迎大家在评论区批评指正

希望接下来的内容能够在大家学习ES6的过程中给予一点帮助

ES的定义
即ECMAScript,脚本语言的规范

其中的ECMA的全称是全称:European computer manufacturers association欧洲计算机制造联合会,后改名为ECMA国际

ES新特性指的是JavaScript的新特性.

为什么学ES
概括为—-更方便更高能

接下来进入正题:

1.let声明

let a = 233,翻译就是让a等于233,简直语义化啊!

使用方式(就是变量声明啦)

1
2
3
4
let a;
let b, c;
let d = 100;
let e = 666, f = 'hhh', g = [];

特性

  1. 变量不能重复声明,否则报错
    (没错,var是可以重复的)
  2. 增加块级作用域
    (ES5中有三种作用域:全局、函数、严格模式中的eval)
    C/C++转过来的简直感动

举个栗子:

1
2
3
4
{
let a = '我在一个块里面';
console.log('这是第1个:' + a);
}

上图的运行结果:
这是第1个:我在一个块里面

1
2
3
4
{
let a = '我在一个块里面';
}
console.log('这是第2个:' + a);

上图的运行结果
报错:a没有定义
补充一点,if、else、while、for等也可以形成块级作用域

  1. 取消变量提升
1
2
3
4
console.log('我是' + Var);
console.log('我是' + Let);
var Var = 'var';
let Let = 'let';

上图运行结果:
一个报错一个undefined
(undefined是声明提升但是赋值不提升导致的)

  1. 依旧有作用域链

    2.const声明

就是常量啦

使用方式

1
2
const A = "必须要初始化(赋值)";
//常量命名规范是:大写大写大写!!!

特性

  1. 一定要赋初始值
  2. 赋值完成后不可修改(毕竟声明的是常量)
  3. 也有块级作用域
  4. 对于用const声明的数组和对象,可以修改其元素

3.新特性:解构赋值

字面意思就是把结构拆解然后赋值?
关于这个东西呢直接举例子比较好
数组的解构赋值

1
2
3
const ARRAY = [1,2,3,4];
let array = [a,b,c,d] = ARRAY;
console.log(a,b,c,d);

上图运行结果:
1 2 3 4
awsl!!!!怎么样,是不是爽的不要不要的?!
对象的解构赋值

1
2
3
4
5
6
7
8
9
10
const MyInfo = {
name:'Serio',
ablity:'TouchFish',
TouchFish:function(){
console.log('没人比我更懂摸鱼');
}
};
let InfoOfMine = {name,ablity,TouchFish} = MyInfo;
console.log(name,ablity);
TouchFish();

上图运行结果:
Serio TouchFish 没人比我更懂摸鱼
其中对 对象的方法 进行解构是最常用的,为了偷懒 方便
需要注意的是,各个元素的名字需要一致,否则报错。

4.新特性:模板字符串

孔丙己便涨红了脸,额上的青筋条条绽出,争辩道,“ES5不能……换行!……ES6的事,还用换行吗?”接连便是难懂的话,什么“作用域链”,什么“闭包”之类,引得众人都哄笑起来:店内外充满了快活的空气

使用方式

新旧对比

1
2
3
4
5
6
let str = '换行昂昂昂\
要加上斜杠,或者加号连接'
+ '不然会报错的';
let strES6 = `没错,现在我们用\`(反引号,就是键盘上和~一个位置那个)
表示字符串惹~
换行很方便的~~~`;

特性

  1. 可以直接换行了
  2. 可以直接拼接变量

(配合高贵的${})

1
2
3
let a = 3;
let str = `我要给这篇文章一个${a}连`;
console.log(str);

上图运行结果
提前感谢
感谢各位读者,感谢一路走来给予我支持和帮助的老师和前辈….阿巴阿巴(手动狗头)

5.新特性:对象属性声明简化

使用方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
     let name = 'Serio', 
level = '蒟蒻';

function showAbility(){
console.log('BUG + 1');
}
//没错,直接将变量作为自身属性
const FEIWU = {
name,
level,
showAbility,
//函数的声明也可以不用写function了
checkMoney(){
console.log(`果然没钱`);
}
}
FEIWU.showAbility();
FEIWU.checkMoney();

上图运行结果:
在这里插入图片描述

特性
似乎…没啥特性

6.新特性:箭头函数

“你知道吗,箭头函数的语法糖,有四种写法”

使用方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//第一种:()=>{}
let fn = (a, b)=>{
console.log(a + b);
}
fn('啊','是箭头函数');
//第二种:只有一个参数,省略()
fn = a =>{
console.log(`笑死我${a}`);
}
fn(2333);
//第三种:方法体只有一条语句,省略{}
fn = (a,b)=>console.log(a + b);
fn(1,1);
//第四种:方法体只有一条语句且为return,直接写return的内容
fn = (a)=>a + 1;
console.log(fn(9));

上图运行结果
在这里插入图片描述

特性

  1. 静态this
    对于function声明的函数,谁调用this就指向谁;
    但是对于箭头函数来说,其this永远指向函数声明时的作用域下的this,并且不能被call,bind等方法改变
1
2
3
4
5
6
7
8
9
10
11
12
13
14
//写成这样方便复习上一个知识点
let whereIsThis1 = function(){
console.log("1普通函数" + this);
}

let whereIsThis2 = ()=>{
console.log("2箭头函数" + this);
}
const WhereRU = {
whereIsThis1,
whereIsThis2
}
WhereRU.whereIsThis1();
WhereRU.whereIsThis2();

上图运行结果
普通函数---this指向对象,箭头函数---this指向window
所以箭头函数适用于与this无关的情况

  1. 不能实例化对象(就是不能作为构造函数,也就是不能new)
  2. 没有arguments了(悲伤)
  3. 多种省略形式(没错就是开头的几种形式)

7.函数参数默认值

说实话看到这个新特性的时候我第一也是唯一的反应就是————
原来以前没有吗???
使用方式

1
2
3
4
5
6
//好了,现在c有默认值了
function calc(a,b,c = 220){
console.log(a + b + c);
};
calc(100,200);
calc(100,200,1014);

上图运行结果
520 1314

8.rest参数

“arguments的离去,是rest的要求,还是es6的不挽留”
(其实arguments不仅还能用,还挺好用的)
使用方法

1
2
3
4
5
//...是扩展运算符 不可以省略
function UltramanBros(a,b,...args){
console.log(a,b,args);
}
show("佐菲","初代","赛文","艾斯","泰罗","雷欧");

上图运行结果
超出的四个会以数组形式保存
…是扩展运算符,能将数组展开成参数序列,
所以传入…args相当于传入了n个参数,
超出的四个参数依次对应,然后存入args中

9.Symbol类型

JS的第七种数据类型(话说前六种是啥来着)
这次我们先说特性
特性

  1. 值唯一,解决了命名冲突问题
  2. 不能与其他类型的数据进行运算
  3. Symbol类的对象不能用加强for循环(for in),但是可以用Reflect.ownKeys

我对Symbol的理解:
就是根据你传入的内容产生一个(伪)随机的、不重复的值,感觉原理就是哈希表(散列表)
(如果没错的话,那么理解哈希表会帮助理解Symbol)

使用方式

1
2
3
4
5
6
7
8
9
10
11
12
13
//第一种声明方式
let s1_1 = Symbol('第一类');
let s1_2 = Symbol('第一类');
//s1_1和s1_2依旧是不同的值
//keyFor()方法就是根据值反过来找下标
console.log(s1_1 === s1_2);//false
console.log('第一类声明的索引' + Symbol.keyFor(s1_1));//undefined
//第二种声明方式
let s2_1 = Symbol.for('第二类');
let s2_2 = Symbol.for('第二类');

console.log(s2_1 === s2_2);
console.log('第二类声明的索引' + Symbol.keyFor(s2_1));

上图运行结果
在这里插入图片描述
第一类声明没有“记录机制”,同样的内容是不同的值,而且不能根据值反过来找索引

第二类则有“记录机制”,与第一类相反

运用
有什么用?
参考一下哈希表,至少能够用来安全、随机、可查询地在数组中存储数据….(啊,我也不知道)
(哦哦我是蒟蒻,所以我也不该知道—-骄傲!)

Symbol内置值
这个对于我来说有点晦涩,而且看上去用处不是很大,
这里先暂时跳过,等我学懂了再补上….

10.迭代器

ES6中新增for-of遍历
迭代器是用来做什么的呢?就是用来遍历的,为不同的数据结构提供了同样的访问方式:
只要某种数据结构中具备iterator的接口,就可以使用迭代器遍历

首先我们来说一下两种迭代遍历:
for-in和 for-of

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
        const SZ3L = ['woc','NB','666'];
//普通for不用let就只能用立即执行函数了
for(var i = 0; i < SZ3L.length; i ++){
(function(a){
console.log('普通for循环',a);
})(i);
}

for(let i in SZ3L){
console.log('for-in循环:' + i);
}

for(let i of SZ3L){
console.log('for-of循环:' + i);
}

上图运行结果
在这里插入图片描述
可以看到,
for-in是遍历数组的下标(键),
for-of则是遍历数组的值

浅析原理
(我是废物,说不清楚)
(还得再研究一下,主要还是Symbol没学懂)
迭代器接口
迭代器工作过程简单概括为以下3步:
1.创建一个指针对象,指向当前数据结构起始位置
2.调用对象的next方法,指向下一个成员并返回一个包括value和done属性的对象
(注意是next方法返回对象)
重复这个过程,直到指向最后一个成员
3.修改done属性为true,遍历完成,停止调用next

1
2
3
4
5
6
let iterator = SZ3L[Symbol.iterator]();

console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());

上图运行结果
在这里插入图片描述
其中,done属性是表示是否遍历完成,当访问到最后一个数据时,done的属性从false变为true,迭代器停止遍历

现在来手写一个迭代器
经过多年的研究之后,我为各位读者量身定义了reader对象,
并手写一个迭代器遍历appearance属性数组

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
const reader = {
salary:"月薪10k起步",
appearance:[
'女美男帅',
'墨发雪肌',
'壮得一批'
],
//迭代器
[Symbol.iterator](){
//先初始化一个索引
let index = 0;
//要返回一个类
return{
//类里有next方法
//这里利用了箭头函数指针是静态的这一特性
next:()=>{
if(index < this.appearance.length){
index ++;
return {value:this.appearance[index], done:false};
}else{
return {value:undefined, done:true};
}

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

上图运行结果
女美男帅 墨发雪肌 壮的一批

11.生成器

生成器是一个特殊的函数,用于更好地解决异步编程
(虽然还是已经被更更更好的方法替代了,不过还是得学)
使用方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//记得加星号;这不是指针;
function * myFriends(){

console.log('后端学习打卡时长排名的人数显示器');
yield '阿波';
console.log('明明是嵌入式的实验室却专攻后端');
yield '陈大爷';
console.log('算法很强的后端并且还在学Unity做游戏');
yield '豪老板';
}

let iterator = myFriends();
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());

上图运行结果
(为什么都是后端?巧合吧)
在这里插入图片描述
解析
yield相当于一条有名字的分界线,我们可以通过迭代器的next方法执行每一部分的内容

第一次调用next时,执行第一条分界线以上的内容
第二次调用next时,执行第二条以上,第一条以下的内容
以此类推…

使用方式2
生成器 和 next方法 都可以传参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
function * gen(a){
console.log('这是分界线1里的' + a);
let one = yield '分界线1';

console.log('分界线1的返回值' + one);
let two = yield '分界线2';

console.log('分界线2的返回值' + two);
let three = yield '分界线3';
}

let iterator = gen('一个参数');
console.log(iterator.next());
console.log(iterator.next(233));
console.log(iterator.next());
console.log(iterator.next());

上图运行结果
在这里插入图片描述
生成器gen传参和普通方法一样

next方法的参数,是作为上一条分界线的返回值

比如,第二次调用next,其参数作为 yield ‘分界线1’ 的返回值
要是没有传递参数,那么yield的返回值为undefined

特性

  1. 关键字function与函数名称中间有个 *
  2. 使用了yield表达式
  3. 直接调用会返回一个迭代器对象

运用
说是优化异步编程的,那么我们来看看没有生成器的时候存在的问题:回调地狱

回调函数:将一个函数作为参数传递,但是这个函数不会立刻执行,而是会等待某个条件触发才执行
回调地狱:异步明明是没有固定执行顺序的,那么如果我们偏要它有顺序,就会出现下图这样的结构

1
2
3
4
5
6
7
8
9
10
setTimeout(function () {  
console.log('3s时执行第一层');
setTimeout(function () {
console.log('5s时执行第二层');
setTimeout(function () {
console.log('6s时执行第三层');
//扶我起来,我还能继续嵌套
}, 1000)
}, 2000)
}, 3000)

如果代码量少还好受,要是多了就不好说了
这种回调函数的嵌套就是回调地狱
所以我们可以通过一些方式改善这种情况,比如用生成器:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
function one(){
setTimeout(()=>{
console.log('3s时执行第一层');
g.next();
},3000)
}
function two(){
setTimeout(()=>{
console.log('5s时执行第二层');
g.next();
},1000)
}
function three(){
setTimeout(()=>{
console.log('6s时执行第三层');
g.next();
},1000)
}
function * gen(){
yield one();
yield two();
yield three();
}
let g = gen();
g.next();

上图运行结果
在这里插入图片描述
其实上面还有个一个点可以提一下,就是let明明没有了提升,g却依旧能被上面的函数访问,
和别人讨论了一下觉得应该是由于function声明的时候函数体不会展开,此时g也就没有被访问;等到g.next执行,one,two,three依次执行的时候,才依次展开,此时就可以通过作用域链向上访问到g从而能再次调用g.next…阿巴阿巴(反正大概就是那个意思)

12.Promise

promise是一个构造函数,可以用来封装异步操作,并获取到其成功和失败的结果然后据此作出反应
使用方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
//一个promise对象有三种状态:初始化状态、成功状态、失败状态
const p = new Promise(function(resolve, reject){
//里面要封装一个的操作
//(大多数是异步,大多数是异步,但是你要同步也可以)
setTimeout(function(){
//执行resolve方法之后,p变为‘成功’状态
let data1 = '成功了!';
resolve(data1);//promise实例化对象的状态就会变成成功

//执行reject方法之后,p变为‘失败’状态
let data2 = '失败了!';
reject(data2);
},1000);
});


//成功的话执行第一个函数,失败的话执行第二个函数
p.then(function(value){
console.log('这是成功了:' + value);
}, function(reason){
console.log('这是失败了:' + reason);
})

上图运行结果
在这里插入图片描述
从结果来看,似乎在遇到resolve方法之后就结束了而不是继续往下执行
(Promise的状态一旦变化,就不会再改变了)
另外介绍一下catch方法

1
2
3
4
//catch方法大体上就相当于只写then方法的后半部分
p.catch(function(reason){
console.log('这也是失败了,不过语法糖比较甜对吧' + reason);
})

运用
首先我们来回忆一下原生JS的AJAX
现在准备一个这样的JSON文件

1
2
3
{
"key":"NB"
}

然后(这里是同一目录下)写AJAX

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
httpRequest = new XMLHttpRequest();
if (!httpRequest) {
alert("创建请求失败");
}
httpRequest.open("GET", "./JSONtest.json");

//莫得后端,孤寡前端人只能本地玩单机

httpRequest.send();
httpRequest.onreadystatechange = function () {
if (httpRequest.readyState === 4) {
if (httpRequest.status === 200) {
var data = JSON.parse(httpRequest.responseText);
console.log('AJAX' + data['key']);
//别忘了和data.key的区别
}
else {
console.error('请求失败');
}
}
}

上图运行结果
AJAXNB

接下来我们来演示一次传说中的封装!!!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
const  P = new Promise((resolve, reject)=>{
const xhr = new XMLHttpRequest();
if(!xhr){
console.error('创建请求失败');
}

xhr.open("GET","./JSONtest.json");

xhr.send();

xhr.onreadystatechange = function(){
if(xhr.readyState === 4){
if(xhr.status === 200){
let data = JSON.parse(xhr.responseText)['key'];
resolve(data);
}else{
reject(xhr.status);
}
}
}
}
);
P.then(function(data){
console.log('你的AJAX生了,是个' + data);
},function(reason){
console.log('你的AJAX是个男的' + reason);
})

“就这?就这?这不就是把ajax装进Promise里面吗?我人傻了”
“大家懂的都懂,这种博主老水怪了
上图运行结果

本地运行,请求失败
服务器上运行,请求成功

特性(写这个的时候有点困,估计很多问题,后面再改改,现在大家看看就行)

  1. Promise.then方法的返回值:不写return默认返回一个Promise对象(是被处理之前的Promise)

第一种:内部 回调函数 返回非Promise类型

1
2
3
4
5
6
7
8
9
10
11
    const P = new Promise((resolve,reject) => {
resolve('abab');
});

const result = P.then(value => {
console.log(value);
return '我是第一种返回值(非Promise类型)';
},reason => {
})

console.log(result);

上图运行结果
在这里插入图片描述
第二种:内部 回调函数 返回Promise类型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
const P = new Promise((resolve,reject) => {
resolve('abab');
});

const result = P.then(value => {
console.log(value);
//套娃,返回一个Promise
return new Promise((resolve, reject) => {
//reject使返回的这个Promise的状态为‘失败’
reject('第二种类型:最内部promise的状态决定最终的状态')
})
},reason => {
})

console.log(result);

上图运行结果
在这里插入图片描述
第三种:throw

1
2
3
4
5
6
7
8
9
10
11
12
13
const P = new Promise((resolve,reject) => {
resolve('abab');
});

const result = P.then(value => {
console.log(value);
return new Promise((resolve, reject) => {
reject('第三种类型:抛出错误');
})
},reason => {
})

console.log(result);

上图运行结果
在这里插入图片描述
通过观察以上三种情况,我们发现:这形成了一个链…也就避免了回调地狱的情况……..

(今天写不动了…好困…团队的人还在商量着今晚去吃自助的事情…又困又饿…以后找个时间一定把这里补起来)

(时隔几天,考完了高数….promise剩下的内容以后补充)

13.Set对象

那个橘子味的夏天,少年回忆起了蝉鸣和STL类库…

特性

  1. 拥有iterator接口,可以使用迭代器和扩展运算符(…)
  2. 类似于数组,但是具有唯一性,即元素不重复

属性/方法

  1. size 返回元素个数
  2. add 增加一个新元素,返回增加元素后的集合
  3. delete 删除元素,返回一个布尔值
  4. has 查询是否包含某个元素,返回一个布尔值
  5. clear 清空,没有返回值(或者说返回undefined)

代码实例
先单独说一下add

1
2
3
4
5
6
7
8
9
10
let s = new Set();
//可以传入一个可迭代对象作为参数,参数用于初始化这个集合
let s2 = new Set(['甲', '乙', '丙', '乙', '甲']);

console.log(s2);
//add方法
s2.add('one','two');
s2.add(['a','b']);
s2.add(...['1','2']);
console.log(s2);

上图运行结果
在这里插入图片描述
都没什么特别的,
需要提一下的就是如果传入多个参数,只有第一个有效(不仅局限于add,delete,has等也是如此)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
let s = new Set();
//可以传入一个可迭代对象作为参数,参数用于构造这个集合
let s2 = new Set(['甲', '乙', '丙', '乙', '甲']);

// console.log(s2);
s2.add('one','two');
s2.add(['a','b']);
s2.add(...['1','2']);
// console.log(s2);

//参数 乙 无效
console.log(s2.delete('甲','乙'));
console.log(s2.delete('不存在的元素'));
console.log(s2.add('520'));
console.log(s2.size);
//参数666无效
console.log(s2.has('丙','666'));

console.log(s2.clear(),s2);

上图运行结果
在这里插入图片描述
运用
1.数组去重

1
2
3
4
let arr = [1,2,3,3,2,1];
//用arr创建一个集合,然后展开得到1,2,3再放进数组
let s = [...new Set(arr)];
console.log(s);

上图运行结果
1 2 3
2.求交集
这里顺便介绍:

14.filter

过滤器,遍历每个元素进行筛选
代码实例

1
2
3
4
5
6
7
8
9
10
11
let arr = [1,2,3,2,1];
//可以传三个参数,
//顾名思义,结合输出结果不难理解
let arr2 = arr.filter((value,key,arr)=>{
console.log('这是value',value);
console.log('这是key',key);
console.log('这是arr',arr);

return value > 2 ? true : false;
})
console.log('这是过滤之后的结果',arr2);

数组长度是5,函数执行了5次遍历了每个元素,筛选出了大于2元素
遍历5次,结果只剩一个3

好了我们继续看我们的求交集

1
2
3
4
5
6
7
8
9
let arr = [1,2,3,4,3,2,1];
let arr2 = [1,2,1];
let s2 = new Set(arr2);

let s1 = new Set(arr.filter((value)=>{
return s2.has(value) ? true : false;
}));

console.log(s1);

1 2
3.求并集
这个就没啥说的了

1
2
3
4
let arr = [1,2,3];
let arr2 = [3,4,5];
let s = new Set([...arr,...arr2]);
console.log(s);

在这里插入图片描述
4.求补集
其实也就和求交集一个意思

1
2
3
4
5
6
7
8
9
let arr = [1,2,3,4];
let arr2 = [1];
let s2 = new Set(arr2);

let s = new Set(arr.filter((value)=>{
return s2.has(value) ? false : true;
}));

console.log(s);

不过这里有八十岁老爷爷看了都说牛逼的简化:

1
2
3
4
5
6
7
8
let arr = [1,2,3,4];
let arr2 = [1];

let s = new Set(arr.filter((value)=>{
return !new Set(arr2).has(value);
}));

console.log(s);

2 3 4

15.map对象

其实就是键值对
特性

  1. 又是一个自带iterator接口的

属性/方法

  1. size 长度
  2. set 添加元素
  3. has 查询是否存在
  4. clear 清空
  5. get 通过键传入值
  6. delete 通过键删除元素

代码实例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
let m = new Map();
m.set(233,'键233的值');

let obj = {name:'一个对象'};
m.set(obj,'键对象的值');
console.log('m.get(233):', m.get(233));
console.log('m.get(obj):', m.get(obj));
console.log('m.has(obj)',m.has(obj));

console.log('m.size:',m.size);

console.log('clear之前:',m);
m.clear();
console.log('clear之后:',m);

在这里插入图片描述

16.class类

先回顾一下构造函数实例化对象

1
2
3
4
5
6
7
8
9
10
11
12
function Person1(name, age){
this.name = name;
this.age = age;
}

Person1.prototype.speak = function(){
console.log('I\'m the ' + this.name +' DEEP! DARK! FANTASY♂!');
}

let somebody1 = new Person1('黑暗之王',18);

somebody1.speak();

在这里插入图片描述

class类实例化对象(javar狂喜)

1
2
3
4
5
6
7
8
9
10
11
12
13
class Person2{
//构造器
constructor(name, age){
this.name = name;
this.age = age;
}
speak(){
console.log('我是' + this.name + ',我是不朽的');
}
}

let somebody2 = new Person2('玛尔加尼斯',5);
somebody2.speak();

在这里插入图片描述
static静态
不论新旧,都有这样一手操作:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Coder1{
//什么都没有哦
}
function Coder2(){
//意思是程序员一无所有[bushi
}
Coder1.name = '知鑫';
Coder2.name = '雨溪';


let coder1 = new Coder1();
let coder2 = new Coder2();

console.log('红尘作伴,代码潇潇洒洒~');
console.log(coder1.name,coder2.name);

快快乐乐,昂第佛爱德~
两个undefined
通过上述方式添加的成员,只属于构造函数而不属于实例化对象.

上述写法相当于
(static只能在class类里面合法)

1
2
3
4
5
class Coder3{
static name = '日娃';
}
let coder3 = new Coder3();
console.log('无名英雄,程序员:' + coder3.name);

无名英雄的名字当然是undefined啊!
undefined
继承
又让我们先回顾构造函数如何继承吧
(JS高级的原型链…说实话我也快忘完了)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
function Win10(info, bugs){
this.info = info;
this.bugs = bugs;
}
function Win11(info, bugs, moreBugs){
Win10.call(this,info,bugs);
this.moreBugs = moreBugs;
}

Win11.prototype = new Win10;
Win11.prototype.constructor = Win11;//纠正Win11的构造函数

Win11.prototype.start = function(){
console.log('绿屏了');
}

let newSystem = new Win11('最后一代?从来没说过','挺多','更多了');

console.log(newSystem);
newSystem.start();

在这里插入图片描述
啥?为啥方法要写到prototype里面而不是直接写到对象里面?(上一节static静态才说了

class继承

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class Win10{
constructor(info,bugs){
this.info = info;
this.bugs = bugs;
}
}

class Win11 extends Win10{
constructor(info,bugs,moreBugs){
super(info,bugs);
moreBugs = moreBugs;
}

start(){
console.log('绿屏了');
}
}

let mySystem = new Win11('谁说win10是最后一代了?','有bug','更多bug!');
mySystem.start();
console.log('mySystem:',mySystem);

运行结果
虽然看上去和JAVA差不多了,但是实际上还是原型链的封装
子类对父类方法的重写也一样,其实只是原型链的知识…

17.get与set

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Coder{
get whyWeLive(){
console.log('为了吃饭');
return false;
}

set whyWeLive(dream){
console.log('为了理想');
return true;
}
}

let us = new Coder();
let ans = us.whyWeLive; //访问,触发get部分
console.log(ans);
us.whyWeLive = '为更多的人创造更好的世界';//修改,触发set部分

注意whyWeLive是属性不是方法,
get修饰是指,在该属性被访问的时候,调用后面的函数
set修饰是指,在该属性被修改的时候,调用后面的函数

在这里插入图片描述
人生来不是为了吃饭,我们还有理想

18.数值扩展

感觉这部分也没什么好说的,了解一下就行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
//1.误差(最小精度)
console.log('0.1 + 0.2 === 0.3', 0.1 + 0.2 === 0.3);
function equal(a, b){
return Math.abs(a - b) < Number.EPSILON ? true : false;
//EPSILON是一个极其小的数字
}
console.log('equal(0.1 + 0.2, 0.3):', equal(0.1 + 0.2, 0.3));
//2.更多的进制
let a = 20;
let b = 0b10100;
let c = 0o24;
let d = 0x14;
console.log('十进制', a, '二进制', b, '八进制', c, '十六进制', d);
//3.更多方法
console.log('Number.isNaN(100 / 0):', Number.isNaN(100 / 0));
console.log('Number.isFinite(100 / 0):', Number.isFinite(100 / 0));
console.log('Number.isInteger(2.3):', Number.isInteger(2.3));
console.log('Number.parseInt(\'2333ababa66\'):', Number.parseInt('2333ababa66'));
console.log('Number.parseFloat(\'1.7321abcd\'):', Number.parseFloat('1.7321abcd'));
console.log('Math.trunc(4.33):', Math.trunc(4.33),'Number.parseInt(\'4.33\'):', Number.parseInt(4.33));
console.log('Math.sign(0):',Math.sign(0),'Math.sign(-666):',Math.sign(-666));

唯一需要注意的是这里的equal方法是用EPSILON属性实现的,不是JS自带的方法
在这里插入图片描述

19.Object方法扩展

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
//1.Object.is 判断两个值是否完全相等
console.log('Object.is(NaN, NaN)',Object.is(NaN, NaN),'NaN === NaN',NaN === NaN);

//2.Object.assign 合并对象
function A(name, age){
this.name = name;
this.age = age;
}

function B(name,sex){
this.name = name;
this.sex = sex;

}

let a = new A('A',18);
let b = new B('B','女');

console.log('Object.assign(a,b)',Object.assign(a,b));

//3.Object.setPrototypeOf 设置原型对象
//4.Object.getPrototypeof 获取原型对象
let C = {
name: 'C'
};
let D ={
age: 33
}
Object.setPrototypeOf(C, D);
console.log('Object.setPrototypeOf(C, D):' , C);
console.log('Object.getPrototypeOf(C):' , Object.getPrototypeOf(C));

在这里插入图片描述
在这里插入图片描述

20.module模块化

把丑陋的代码实现包起来,只留出接口给外面看
(比如写一个冒泡排序,接口名字叫做快速排序,别人调用的时候就会觉得————好耶)

而且模块之间的内容是互不影响的,避免了污染

首先在同一目录下创建一个moduleTest.js文件,内容是

其中export修饰的内容会被暴露

1
2
3
4
5
6
7
export let date = '2021/07/05';

export function myRecentLife(){
console.log('还在进行因为疫情被推迟的军训..');
console.log('我想躺着写代码啊!!!');
console.log('我想吃肉!!!');
}

然后另一边,我们这样写

1
2
3
4
5
6
7
8
9
10
11
<script type="module">
//模块化必须在服务器上测试
//(本地折腾半天没有输出...)
import {date} from "./moduleTest.js";
console.log(date);
import * as m from './moduleTest.js';
//这个语句很像SQL,语义化也很强
//*是啥?参考一下css的*就知道了
console.log(m);
m.myRecentLife();
</script>

上图运行结果(一定要在服务器上运行啊!不然没有反应的
在这里插入图片描述
注意事项
假如引入的两个模块中有重名内容,
比如
在这里插入图片描述
那么我们可以使用关键字as操作一手:

1
2
3
4
import {date} from "./moduleTest.js";
import {date as date2} from "./moduleTest2.js";

console.log("date:",date,"\ndate2:",date2);

(记得要在服务器上运行啊!!!)
在这里插入图片描述

后记

ES6大概就这样结束了,不过我还是想写下这多余的话

ES6更新了很多东西,这篇笔记是我一边学习一遍写代码做记录产生的,也是第一次接触到其中一些内容,所以难免有漏掉部分知识点,和理解分析不到位的情况,希望大家包涵谅解

后面如果有机会的话,我也会继续做ES相关的内容

祝大家能够不断进步


文章作者: Serio
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Serio !
  目录