ES6 新特性
文章目录
1.Let
- let 不存在变量提升的问题
- 在代码块内有效,代码块不一定是指的花括号,比如
if
语句后面的内容,while 后面的内容。
比如下边这个,用var就不行,因为他的作用域是属于全局的,只有一个 i
,循环到最后成 3 了,显然不对。
for (var i = 0; i <itmes.lenth:i++){
itmes[i].render=5
}
2.const
- 一般使用大写。
- 常量不能修改。
- 是块级作用域
- 如果
const
指向的数组或者对象,对其中的操作是可以的。这样对数组进行声明是可以的。
出现了 除了单引号,双引号,还可以使用 反引号 ``
3.声明对象
<script>
let name="zhao";
let chang=function(){
console.log("peng");
}
const school={
name,
chang
}
</script>
4.rest 参数
<script>
function datea(...args){
console.log(args);
}
datea("1","2","3");// 做个是打印出来是个数组,而不是对象
</script>
打碎,用这个方法。
<script>
const kuaizhi=["王太利","肖阳"];
const fenghuagn=["争议","玲花"];
const hebing=[...kuaizhi,...fenghuagn];
const shanyan=["E","G","M"];
const divarr=[...shanyan]; // 数组拷贝
</script>
5.迭代器
迭代器是一种接口,为各种不同的数据结构提供统一的访问机制。任何数据结构只要部署了 iterator
就可以完成遍历操作。
ES6 中创建了一种遍历命令 for of
循环,能对一下类型进行遍历
- Array
- Argument
- Set
- Map
- String
- TypeArray
- Nodelist
工作原理,就是创建指针对象,指向当前结构体的起始对象;
第一次调用对象的 next 方法,指针一直往后移动,直到指向了最后一个对象
每次调用 next 方法,都会返回一个 包含 value 和 done 属性的对象。
6.生成器
生成器其实就是一个特殊的函数,一般使用异步编程。
1.声明和使用的特殊之处
function* gen() { // 声明特殊
console.log("你好");
}
let a = gen();
a.next(); // 直接调用还不行,需要使用next函数调用
2.yeld 函数
- 既然能使用next,就可以使用
for of
方法;
3.yeald 用于异步调用。
<script>
function* gen(arg) { // 声明特殊
console.log(arg);
let one = yield 111;
console.log(one);
let two = yield 222;
console.log(two);
yield 333;
}
let iter = gen("AAA");
console.log(iter.next());
console.log(iter.next("aaa"));
console.log(iter.next("bbb"));
// next 可以传参,传过去的参数相当于是上一个函数的返回结果
</script>
异步操作
- 异步编程一般适用于 文件操作,网络操作,还有 (axios)数据库操作
- 1s 后控制台输出 111, 2s 后输出222, 3s 后输出333.
这样的问题就是,如果要进行,如果回调比较多,就会有回调里面用回调,一层套一层。
<script>
setTimeout(() => {
console.log(111);
setTimeout(() => {
console.log(222);
// 如果再继续执行,你会发现这个东西在不断的更新
}, 2000)
}, 1000)
</script>
1.生成器函数的使用,实现异步
<script>
function one() {
setTimeout(() => {
console.log("aaa");
iter.next();
}, 1000)
}
function two() {
setTimeout(() => {
console.log("bbb");
iter.next();
}, 2000)
}
function three() {
setTimeout(() => {
console.log("ccc");
iter.next();
},3000)
}
function* gen() {
yield one();
yield two();
yield three();
}
let iter = gen();
iter.next();
</script>
2.再一个小例子
用户依次取得 订单数据,用户数据,商品数据。
function getone() {
setTimeout(() => {
let b = "用户数据";
A.next(b);
}, 1000);
}
function gettwo() {
setTimeout(() => {
let s = "订单数据";
A.next(s);
}, 1000);
}
function getthree() {
setTimeout(() => {
let m = "商品信息,第三个函数";
console.log(m);
A.next(m)
}, 1000)
}
function* gin() {
yield getone();
let ss = yield gettwo();
console.log(ss);
let m = yield getthree();
console.log(m, "第三个函数");
}
let A = gin();
A.next();
promise语法
// promise 相当于是一个语法糖
// promise 成功的话,就调用第一个方法,失败的话,就调用第二个方法
const p = new Promise(function (resolve, reject) {
setTimeout(function () {
console.log("很好");
let a = "成功";
resolve(a); // 调用成功这个方法
}, 1000);
});
// 调用promise对象的then 方法
// 成功的话,掉第一个方法,失败的话,就调第二个方法
p.then(function (value) {
console.log(value);
}, function (err) {
console.log(err);
});
Promise三种状态
-
pending:初始状态,完成或失败状态的前一个状态
-
fulfilled:操作成功完成
-
rejected:操作失败
async 和 await
async 和 await 两种语法相结合,就可以让一步代码像同步代码一样。
async 函数
- 返回值是promise 对象。
- promise 对象的结果 async 函数执行的返回值决定。
async function fn() {
// 返回一个结果,如果这个结果不是一个 promise 对象,
// 那么返回结果就是正确的
// 如果一个 promise 对象的输出是成功的,那么就是成功的。
return "尚硅谷";
}
const a = fn();
console.log(a);
成功的:
如果是报出的异常呢?
<script>
async function fn() {
// 返回一个结果,如果这个结果不是一个 promise 对象,
// 那么返回结果就是正确的
// 如果一个 promise 对象的输出是成功的,那么就是成功的。
throw new Error("出错了")
}
const a = fn();
console.log(a);
</script>
再写两个小例子试一下
async function fn() {
// 返回一个结果,如果这个结果不是一个 promise 对象,
// 那么返回结果就是正确的
// 如果一个 promise 对象的输出是成功的,那么就是成功的。
throw new Error("出错了")
}
const a = fn();
a.then(() => {
console.log("成功了")
}, () => {
console.log("失败");
});
async function fn() {
// 返回一个结果,如果这个结果不是一个 promise 对象,
// 那么返回结果就是正确的
// 如果一个 promise 对象的输出是成功的,那么就是成功的。
return "你好"
}
const a = fn();
a.then(() => {
console.log("成功了")
}, () => {
console.log("失败");
});
await 函数
- await 必须写在
asycn
的函数中 - await 返回的是
promise
成功的值 - 如果失败了,就是用
try***catch
进行捕捉
小例子
const p = new Promise((resolve, reject) => {
resolve("成功了");
});
async function main() {
try {
let m = await p;
console.log(m);
} catch (e) {
console.log(e);
}
}
main();
// 输出
成功了
输出失败了:
const p = new Promise((resolve, reject) => {
reject("输出失败");
});
async function main() {
try {
let m = await p;
console.log(m);
} catch (e) {
console.log("失败了");
console.log(e);
}
}
main();
再写一个小例子
const p = new Promise(function (resolve, reject) {
fs.readFile("t.txt", (err, data));
if (err) reject(err); // 失败的话报错;
resolve(data); //如果成功
});
p.then(() => {
console.log("成功");
}, () => {
console.log("识别");
})
自己封装一个 axiso 请求;
let p = new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
xhr.open("GET", "http//api.ap/get");
xhr.send(); // 发送请求
xhr.onreadystatechange = function () {
if (xhr.readyState == 4) {
if (xhr.status == 200) {
resolve("请求成功");
console.log("打印成功");
} else {
resolve("请求失败");
console.log("打印失败");
}
}}
});
p.then((varlue) => {
console.log(varlue);
}, (err) => {
console.log(err);
});
七.对象
1.如何声明一个对象
有三种方法
let obj1 = new Object(); // 直接 new 一个
let obj2 = {}; // 使用字面变量创建对象
function Start(name, age) {// 直接使用构造函数
this.name = name;
this.age = age;
this.sing = function () {
console.log("我会唱歌");
}
}
let liudehua = new Start("刘德华", 18);
console.log(liudehua);
- 构造函数一般都是使用
首字母大写
执行 new
的时候,会执行的四件事
- 在内存中创建一个新的对象。
- 用
this
指向这个新对象。 - 使用构造函数的属性,给新对象添加属性和方法
- 返回这个新对象(所以构造函数不包含 return)
2.实例成员和静态成员
- 实例成员就是构造函数内部,通过
this
来添加的成员; - 实例成员只能通过实例化的对象来访问;
- 静态对象能直接添加属性。
- 静态对象,只能使用对象引用。
let obj1 = new Object(); // 直接 new 一个
let obj2 = {}; // 使用字面变量创建对象
function Start(name, age) { // 直接使用构造函数
this.name = name;
this.age = age;
this.sing = function () {
console.log("我会唱歌");
}
}
let liudehua = new Start("刘德华", 18);
console.log(liudehua.name); // 这个就是实例成员
Start.sex = "男"; // 静态成员直接加就行
console.log(Start.sex); // 不能通过实例访问
构造函数存在的问题
构造函数的方法很好用,但是存在浪费内存的问题。
使用构造函数原型
通过原型分配的函数,都是所有对象所共享的。
js规定,每个构造函数都有一个 prototyep 属性,指向另一个对象,注意这个 prototype 是个对象,我们可以把那些个不变的方法,直接定义在 prototype 对象上,这样所有的实例就都可以共享这些个对象了。
let obj1 = new Object(); // 直接 new 一个
let obj2 = {}; // 使用字面变量创建对象
function Start(name, age) { // 直接使用构造函数
this.name = name;
this.age = age;
}
Start.prototype.single = function () {
console.log("我会唱歌");
}
let liudehua = new Start("刘德华", 18);
console.dir(Start);
console.dir(liudehua);
liudehua.single();
此方法可以直接使用,原始数组中,比如 Array 这个关键字。可以执行一些对原有的数组求和等等的操作
Array.prototype.sum = function () {
let sum = 0;
for (let i = 0; i < this.length; i++) {
sum += this[i]
}
return sum;
}
let arr = [1, 2, 3];
console.log(arr.sum());
2.1 函数的内部 this 的指向
调用方法 | this 指向 |
---|---|
普通函数调用 | window |
对象调用 | 该方法所指的对象 |
构造函数调用 | 实例对象,原型对象里的方法都指向实例对象 |
立即执行函数 | window |
通过 call
改变原来函数的指向
function fn(a,b) {
console.log(a+b);
console.log("函数的this" + this);
}
let o={
name:"wang",
age:"li"
}
fn.call(o,1,2)
// 输出
3
Object
2.js 中的闭包问题
- 函数的内部可以使用全局变量
- 函数的外部不可以使用全局变量
- 当函数执行完毕以后,本作用域内的局部变量就会被销毁
闭包是有权访问另一个作用域中变量的函数
一个作用域可以访问另外一个函数内部的局部变量。
function f1() { // f1就是个闭包。
var num = 10;
function f2() {
console.log(num);
}
f2();
}
f1();
闭包的强大作用就是在包的外面访问包的内部
- 闭包的作用就是延伸了变量的作用范围
- 原本 num 在调用就要销毁的,现在不能销毁了,因为还有一个函数
f2
要等着用。
function f1() {
var num = 10;
function f2() {
console.log(num);
}
// f2(); 把执行做个函数变成返回
return f2
}
let m = f1(); // 实际上此时的m就是f2
m();
打印斐波那契列数
function fb(n) {
if (n == 1 || n == 2) {
return 1;
} else {
return fb(n - 1) + fb(n - 2);
}
}
let a = fb(5);
八. 其他的小知识点
Proxy
- proxy 相当于在目标自己按架了一层拦截,对对象的访问,都必须要通过这个拦截。
var obj = new Proxy({}, {
get: function (target, propKey, receiver) {
console.log(`getting ${propKey}!`);
return Reflect.get(target, propKey, receiver);
},
set: function (target, propKey, value, receiver) {
console.log(`setting ${propKey}!`);
return Reflect.set(target, propKey, value, receiver);
}
});