es6 学习笔记
let变量
let和var用法级别一样
let不能重复声明,但是var可以
var varIns = "A";
var varIns = "B"; // 合法
let letIns = "A";
let letIns = "B"; // 不合法
let具有块级作用域,var没有
const变量
const定义后不能修改
const和let一样,只能作用在局部,块级作用域
const SCHOOL = '新蔡一高'
// SCHOOL = 'kkkl' 报错不能修改
const a = 123; //一般是大写
{
const cs = 12
}
// console.log(cs); 和let一样只能作用局部,在块级作用域
const ITEM = ['lk', 'kkl', 'jkjld'];
ITEM.push('jsj');
定义字符串补充:
``我们可以用这个定义字符串,并且换行的时候不用加引号,不会报错
用引号不行,只能用反引号才来使${}表达式转换,否则输出还是原来的样子
console.log("=======es6的新特性===========");
// 可以用``这个符号表示字符串,并且换行不需要加引号和++
let str = `我是
一个字符串`;
console.log(str);
var str1 = `k
lk`;
console.log(str1);
let love = '小王';
let out = `${love}是最好的人`;
let out1 = '${love}是最好的人'; //用引号不行,只能用反引号才来使${}表达式转换,否则输出还是原来的样子
console.log(out1);
console.log(out);
箭头函数
var div = document.querySelector('div');
div.addEventListener('click', function() {
let _this = this;
setTimeout(function() {
// 普通函数this指向有问题我们需要this是指向div而普通函数指向window
// 解决方法1:在定时器外面将this指向div
console.log(this);
_this.style.backgroundColor = 'pink';
console.log(_this);
}, 1000);
// 解决方法2: 将定时器改成箭头函数 箭头函数表示在定义时的作用域就是div
// setTimeout(() => {
// this.style.backgroundColor = 'pink';
// }, 1000);
})
普通函数this指向有问题我们需要this是指向div而普通函数指定时器的回调函数指向window
解决方法1:在定时器外面将this指向div
箭头函数指向就是谁调用的就是谁的this,定时器没有自己的this,向外面找就是div的
rest参数
普通函数中有arguments这个搜集参数
let fu = function() {
console.log(arguments);
}
fu(1, 2, 3);
而普通方式arguments是对象,而es6中rest参数返回的字符串,而字符串有利于操作
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0RDncvJV-1666349132206)(C:\Users\lenovo\AppData\Roaming\Typora\typora-user-images\image-20221006000026251.png)]
rest序列扩展符返回的是数组
function data(...args) {
console.log(args);
}
data('kkl', 'kk', 'huang')
console.log("==========================");
//序列扩展符
const tf = ['xz', 'xl', 'xc'];
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UJ5jRGsT-1666349132207)(C:\Users\lenovo\AppData\Roaming\Typora\typora-user-images\image-20221006000111274.png)]
数组的合并:
利用扩展符将数组结合
// 1.数组的合并
const a1 = ['xh', 'xz'];
const b1 = ['xc', 'xk'];
const c1 = a1.concat(b1); //数组的属性合并函数
console.log(c1);
const c2 = [...a1, ...b1]; 扩展符的特性
console.log(c2);
数组的克隆
// 2数组的克隆
const a2 = ['E', 'G', 'M'];
const b2 = [...a2];
console.log(b2);
Symbol
Symbol是ES6引入的一种新的数据类型
用来表示独一无二的值
他是一种类似于字符串的值,保证值是唯一的
Symbol值不能参与任何一种运算,外部也看不到Symbol的值是多少, 只能知道分别定义两个Symbol一定是不同的
Symbol的作用非常的专一,换句话说其设计出来就只有一个目的——作为对象属性的唯一标识符,防止对象属性冲突发生。
let info1 = {
name: '婷婷',
age: 24,
job: '公司前台',
description: '平时喜欢做做瑜伽,人家有男朋友,你别指望了'
}
let info2 = {
description: '这小姑娘挺好的,挺热情的,嘿嘿嘿……'
}
当数据繁琐多的时候
就会导致一个对象属性有两个会发生冲突
let info1 = {
name: '婷婷',
age: 24,
job: '公司前台',
[Symbol('description')]: '平时喜欢做做瑜伽,人家有男朋友,你别指望了'
}
let info2 = {
[Symbol('description')]: '这小姑娘挺好的,挺热情的,嘿嘿嘿……'
}
这样将两个对象复制就不会出现问题,这样两个属性都会显示,不会被覆盖
let target = {};
Object.assign(target, info1, info2);
输出:
{name: "婷婷", age: 24, job: "公司前台", Symbol(description): "平时喜欢做做瑜伽,人家有男朋友,你别指望了", Symbol(description): "这小姑娘挺好的,挺热情的,嘿嘿嘿……"}
迭代器
迭代器是一种接口,各种数据结构只要在定义的时候定义了Iterator接口(就是对象就具有Iterator成员变量)就可以完成迭代操作
- ES6原生具备Iterator的对象有
- Array
- Arguments
- Set
- Map
- String
- TypedArray
- NodeList
Iterator的使用方法与c++的迭代器相似,创建的时候迭代器变量获取对象,在的迭代器.next()后,next函数返回一个指向数据结构的首地址,使用next进行指针的 移动获取值,不断调用next达到数据结构
const xyj = ['xw', 'xz', 'xh', 'xk'];
for (let v in xyj) {
for in 遍历数组v是索引
console.log(v);
}
for of遍历的数组是value值
for (let v of xyj) {
console.log(v);
}
调用对象的next方法
let iterator = xyj[Symbol.iterator]();
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next()); //结束返回value值为undefined done值为true
调用结果
{value: "A", done: false} // 返回值是一个对象,包含value和done表示是否结束迭代
{value: "B", done: false}
{value: "C", done: false}
{value: undefined, done: true} // 遍历结束后设置done=true
补充for循环遍历
for in 便历出来的是属性的index索引
for of遍历的是value
- 手动给对象添加属性后, for in 是可以将新添加的属性遍历出来 但是for of 不行
for in
的属性是使用[]不可以使用 “.” eg: data[‘index’] instead of data.index
自定义迭代器
现在有一个对象其中有一个stus数组,我们想进行遍历,但是我们不想直接用foreach遍历因为这样会使school对象不安全,达不到面向对象的思想
const school = {
name: '28班',
stus: [
'xiaoh',
'xiaosz',
'xiaoc',
'xiaok'
],
我们现在可以自己定义迭代器
在对象中都有Symbol.iterator属性,指向该对象的默认遍历器方法
我们将Symbol.iterator属性,改写输出为对象的stus的值
在根据stus的长度判断是否结束,当Symbol属性返回对象中的done属性为false就结束next的移动
[Symbol.iterator]() {
let index = 0;
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
};
}
}
}
}
}
生成器
生成器是一个函数,是一个ES6异步编程解决方案, 之前我们异步编程使用的是回调函数
,但是容易形成回调地狱
定义: 生成器函数与就是在普通函数声明前面加入了*
function * gen(){
console.log("hi");
return "GEN OK"
}
我们可以把函数返回的值赋值给变量,变量是一个迭代器,当变量执行了next,如果嵌套可能还是迭代器,如果就只有一层那么就返回值return
function * gen(){
console.log("hi");
return "GEN OK" 返回
}
let p = gen();
console.log(p); // p是gen {<suspended>} 是一个迭代器
let q = p.next() // 执行next 输出hi
console.log(p,q); // p是gen {<closed>} 迭代器 q是迭代器结果{value: "GEN OK", done: true}
生成器函数可以被yield分割
yield是ES6的新关键字,使生成器函数执行暂停,yield关键字后面的表达式的值返回给生成器的调用者。它可以被认为是一个基于生成器的版本的return关键字。
yield关键字实际返回一个IteratorResult(迭代器)对象,它有两个属性,value和done,分别代表返回值和是否完成。
function * gen(){
// ====函数第1部分====
console.log("Part 1");
yield "P1" // == 返回"P1" 不得用return否则后面代码都无效了
// ====函数第2部分====
console.log("Part 2");
yield "P2" // == 返回"P2" 不得用return否则后面代码都无效了
// ====函数第3部分====
console.log("Part 3");
yield "P3" // == 返回"P3" 不得用return否则后面代码都无效了
// ====函数第4部分====
console.log("Part 4");
yield "P4" // == 返回"P4" 不得用return否则后面代码都无效了
// ====函数第5部分====
return "AllEnd" // == 返回"AllEnd" 不得用yield会新开一个部分
}
let f = gen();
console.log(f.next()) // { value: 'P1', done: false }
console.log(f.next()) // { value: 'P2', done: false }
console.log(f.next()) // { value: 'P3', done: false }
console.log(f.next()) // { value: 'P4', done: false }
console.log(f.next()) // { value: 'AllEnd', done: true }
console.log(f.next()) // { value: undefined, done: true }
如果想给某个函数传参数可以将参数写在next函数中,yield可以接收到
function * gen(a){
console.log(a)
let b = yield "===PART B==="
console.log(b)
let c = yield "===PART C==="
console.log(c)
let d = yield "===PART D==="
console.log(d)
}
let it = gen(5); a=5
console.log(it.next(4))
console.log(it.next(3)) b=3
console.log(it.next(2)) c=2
console.log(it.next(1)) d=1
console.log(it.next(0)) // over bound
现在要求1-5s分别输出1-5数字,可以使用回调函数
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();
console.log("==============每秒输出加5的数=============");
function* gen(p1) {
setTimeout(() => {
console.log(p1);
it.next(p1 + 5);
console.log(111);
}, 1000);
let p2 = yield 'p2'
setTimeout(() => {
console.log(p2);
it.next(p2 + 5);
}, 1000);
let p3 = yield 'p3'
setTimeout(() => {
console.log(p3);
it.next(p3 + 5);
}, 1000);
let p4 = yield 'p4'
setTimeout(() => {
console.log(p4);
it.next(p4 + 5);
}, 1000);
let p5 = yield 'p5'
setTimeout(() => {
console.log(p5);
it.next(p5 + 5);
}, 1000);
}
let it = gen(1);
// it.next();
Promise
promise是异步编程的解决方案,从语法上来说promise是一个对象,从它可以获取异步操作的消息,
promise状态不受外界影响promise对象有一个异步操作,有三种状态:pending(进行时),fulfilled(已成功)reject(已失败)
一但状态改变,就不会再变,resolve(已经定型)
const p = new Promise(function(resolve, reject) {
setTimeout(function() {
// let data = '数据成功';
// resolve(data);
let err = '读取失败'
reject(err)
}, 1000)
})
//调用prmoise对象的then方法
p.then(function(value) {
console.log(value); //数据成功调用resolve函数返回的then的第一个函数value值上
}, function(reason) {
console.log(reason);
})
promise读取文件
const fs = require('fs');
// fs.readFile('为学.md', function(err, data) {
// if (err) throw err;
// console.log(data.toString());
// })
// 使用Promise封装
const p = new Promise(function(resolve, reject) {
fs.readFile('为学.md', (err, data) => {
if (err) reject(err)
resolve(data);
})
})
p.then(function(value) {
console.log(value.toString());
}, function(err) {
console.log(err);
})
promise的then方法
then方法是有两个参数的,而这两个参数都是函数,第一个函数是resolve状态的回调函数,
第二个函数是reject状态的回调函数
const p = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('用户数据')
}, 1000);
})
const result = p.then(function(value) {
console.log(value);
}, function(err) {
console.log(err);
})
console.log(result);
读取多个文件
方法一:直接用readFile函数读取,在进行叠加
缺点也是嵌套麻烦
let fs = require('fs');
fs.readFile('木瓜.md', (err, data1) => {
fs.readFile('江南.md', (err, data2) => {
fs.readFile('为学.md', (err, data3) => {
let value = data1 + data2 + data3;
console.log(value);
})
})
})
利用promise读取多个文件
就是利用then进行链式编程
let p = new Promise((resolve, reject) => {
fs.readFile('木瓜.md', (err, data) => {
resolve(data);
});
})
p.then(value => {
//向下继续传递value
return new Promise((resolve, reject) => {
fs.readFile('江南.md', (err, data) => {
resolve([value, data])
})
})
}).then(value => {
return new Promise((resolve, reject) => {
fs.readFile('为学.md', (err, data) => {
value.push(data);
resolve(value);
})
})
}).then(value => {
console.log(value.join('\r\n'));
})