1.Proxy
Proxy 可以理解成,在目标对象之前架设一层"拦截",外界对该对象访问的时候
都必须先通过这一层拦截,相当于提供了一种机制,可以对外界的访问进行过滤和改写
var proxy = new Proxy(target, handler);
Proxy对象的所有用法,都是上面这种形式,不同的只是 handler 参数的写法。其中, new Proxy() 表示
生成一个Proxy实例,target参数表示所要拦截的目标对象, handler 参数也是一个对象,用来定制拦截行为。
- get方法拦截读取,里面有两个参数,传入的对象与属性
- set方法可以设置属性值,但是不会改变原有对象,拦截对象属性的赋值操作
- has方法可以拦截判断该对象中是否有该属性
- 拦截delete操作
拦截对象自身属性的读取操作
2.Reflect
程序在运行的时候去获取对象内部的结构就叫做反射
1.将原先Object对象上定义的一些方法,放入Reflect对象(代码重构)
// Reflect.defineProperty
2.修改了某些Object方法的返回结果
3.让Object操作变成函数行为
- name in obj/delete obj.name 命令式
- Reflect.has(obj.name)/Reflect.deleteProperty(obj,name)
4.Reflect对象的方法和Proxy对象方法对应
//可以让Proxy方便的调用对应的Reflect方法
5.修改指定函数的this指向
求数组的最大值最小值
3.观察者模式
在监听对象属性改变的同时,执行指定其他的业务操作
//先定义一个容器,存放需要执行的业务操作
let box = new Set()
//定义一个函数将所有的业务操作都放进去
let actions = fn => {
box.add(fn)
}
// 定义两个业务
let fn1 = () => {
console.log("业务一")
}
actions(fn1)//传入参数,目的是将业务放入容器中
let fn2 = () => {
console.log("业务二")
}
actions(fn2)//传入参数,目的是将业务放入容器中
//创建一个函数用于生成一个代理对象
let createproxy = target => new Proxy(target, {
set(target, key, value) {
Reflect.set(target, key, value)//设置值
//执行其他业务操作
box.forEach(fn => {
fn()//遍历放在容器中的业务操作,并执行
})
}
})
//定义一个实例对象
let obj = {
name: "wangsu",
age: 23,
grade: 90,
__job__: "IT"
}
//修改属性,调用函数执行
let proxy = createproxy(obj)
proxy.name = "kobe"
4.promise
4.1.promise的定义(面试重点)
Promise是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理和更强大。它由社区
最早提出和实现,ES6将其写进了语言标准,统一了用法,原生提供了 Promise 对象。
所谓 Promise ,简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结
果。从语法上说,Promise是一个对象,从它可以获取异步操作的消息。Promise提供统一的API,各种异步操
作都可以用同样的方法进行处理。
## 4.2 Promise两个特点
1. 对象的状态不受外界影响。 Promise 对象代表一个异步操作,有三种状态: Pending (进行 中)、 Resolved (已完成,又称Fulfilled)和 Rejected (已失败)。只有异步操作的结果,可以决定当
前是哪一种状态,任何其他操作都无法改变这个状态。这也是 Promise 这个名字的由来,它的英语意思就
是“承诺”,表示其他手段无法改变。
2. 一旦状态改变,就不会再变,任何时候都可以得到这个结果.
Promise 对象的状态改变,只有两种可能:从 Pending 变为 Resolved 和从 Pending 变
为 Rejected 。只要这两种情况发生,状态就凝固了,不会再变了,会一直保持这个结果。
就算改变已经发生了,你再对 Promise 对象添加回调函数,也会立即得到这个结果。这与事
件(Event)完全不同,事件的特点是,如果你错过了它,再去监听,是得不到结果的。
了 Promise 对象,就可以将异步操作以同步操作的流程表达出来,避免了层层嵌套的回调
函数。此外, Promise 对象提供统一的接口,使得控制异步操作更加容易。
3. Promise 也有一些缺点。
- 首先,无法取消 Promise ,一旦新建它就会立即执行,无法中途取消。
- 其次,如果不设置回调函数, Promise 内部抛出的错误,不会反应到外部。
- 第三,当处于 Pending 状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)。
- 如果某些事件不断地反复发生,一般来说,使用stream模式是比部署 Promise 更好的选择。
4.3.promise解决文件读取顺序和回调地狱问题
let fs = require("fs")
//封装一个读文件的方法
function reads(path) {
return new Promise((resolve, reject) => {//返回一个promise
fs.readFile(path, (err, data) => {//读取文件数据
if (!err) {
resolve(data.toString())//将读取的数据用resolve返回出去
}
else {
reject(err)//发送拒绝后抛错
}
})
})
}
reads("../data/a.txt")
.then((data) => {//这里函数中的data便是resolve 中返回出来已经读取的数据
console.log(data)
return reads("../data/b.txt")
//这里返回下一个需要读取的文件,在调用一下读取函数,这个函数的返回值是一个Promise
},
(err) => {
throw err
} ).then((data) => {
//由于封装的reads方法返回的是一个promise对象,因此可以继续调用它的then方法
console.log(data)
return reads("../data/c.txt")
},(err) => {
throw err
}).then((data) => {
console.log(data)
return reads("../data/d.txt")
},
(err) => {
throw err
}
).then((data) => {
console.log(data)
},
(err) => {
throw err
}
)
4.4.promise异步解决
由于开始的时候settimeout是一种异步处理函数,那么当程序执行时,程序不会从上到下依次
执行,遇到异步处理时不会等待,此时会造成settimeoutl里面的代码执行可能会在其他代码
执行之后
4.5.promise-all
4.6.promise-race
加载请求速度最快的那个请求
4.7.模拟promise图片加载
//创建一个图片加载函数
function loadImage(url,resolve,reject) {
let img = new Image()
img.src = url
img.onload = function () {
console.log("图片加载成功")
resolve({width:img.width,height:img.height})//在函数中传入参数(图片
的高度宽度)
}
img.onerror = function () {
console.log("图片加载失败")
reject()
}
}
let url="https://ss0.bdstatic.com/94oJfD_bAAcT8t7mm9GUKT-xh_/timg?
image&quality=100&size=b4000_4000&sec=1594954864&di=c86ca29e92ae5ba6ef0400ba
dc17a69a&src=http://a3.att.hudong.com/14/75/01300000164186121366756803686.jpg"
//创建两个函数,分别是图片加载完成和图片加载失败
function resolve(data) {
console.log("图片加载完成,执行某个处理")
console.log(data)
}
function reject() {
console.log("图片加载失败,执行某个处理")
}
loadImage(url,resolve,reject)
5.defineproperty数据劫持
// 这是将要被劫持的对象
const data = {
name: '',
};
function say(name) {
if (name === '古天乐') {
console.log('给大家推荐一款超好玩的游戏');
} else if (name === '渣渣辉') {
console.log('戏我演过很多,可游戏我只玩贪玩懒月');
} else {
console.log('来做我的兄弟');
}
}
// 遍历对象,对其属性值进行劫持
Object.keys(data).forEach(function(key) {
Object.defineProperty(data, key, {
enumerable: true,
configurable: true,
get: function() {
console.log('get');
},
set: function(newVal) {
// 当属性值发生变化时我们可以进行额外操作
console.log(`大家好,我系${newVal}`);
say(newVal);
},
});
});
data.name = '渣渣辉';
//大家好,我系渣渣辉
//戏我演过很多,可游戏我只玩贪玩懒月
6.字符串匹配方法
7.symbol
7.1.基本意义
7.2.symbol作为属性调用
8.Set与Map
8.1.set
8.1.1.常用方法
8.1.2.数组去重
8.1.3.并集,差集,交集
8.2.WeakSet
8.2.1.与set的区别
eakSet 结构与 Set 类似,也是不重复的值的集合。但是,它与 Set 有两个区别。
首先,WeakSet 的成员只能是对象,而不能是其他类型的值。
const ws = new WeakSet();
ws.add(1)
// TypeError: Invalid value used in weak set
ws.add(Symbol())
// TypeError: invalid value used in weak set
上面代码试图向 WeakSet 添加一个数值和Symbol值,结果报错,因为 WeakSet 只能放置对象。
8.2.2.基本概念(面试问到)
其次,WeakSet 中的对象都是弱引用,即垃圾回收机制不考虑 WeakSet 对该对象的引用,也就是说,如果其他对象都不再引用该对象,那么垃圾回收机制会自动回收该对象所占用的内
存,不考虑该对象还存在于 WeakSet 之中。
这是因为垃圾回收机制依赖引用计数,如果一个值的引用次数不为,垃圾回收机制就不会释放
这块内存。结束使用该值之后,有时会忘记取消引用,导致内存无法释放,进而可能会引发内
存泄漏。WeakSet 里面的引用,都不计入垃圾回收机制,所以就不存在这个问题。因此,
WeakSet 适合临时存放一组对象,以及存放跟对象绑定的信息。只要这些对象在外部消失,它
在 WeakSet 里面的引用就会自动消失。
由于上面这个特点,WeakSet 的成员是不适合引用的,因为它会随时消失。另外,由于
WeakSet 内部有多少个成员,取决于垃圾回收机制有没有运行,运行前后很可能成员个数是不
一样的,而垃圾回收机制何时运行是不可预测的,因此 ES6 规定 WeakSet 不可遍历
8.3.map
JavaScript 的对象(Object),本质上是键值对的集合(Hash 结构),但是传统上只能用字符串当作键。这给它的使用带来了很大的限制。
const data = {};
const element = document.getElementById('myDiv');
data[element] = 'metadata';
data['[object HTMLDivElement]'] // "metadata"
上面代码原意是将一个 DOM 节点作为对象data的键,但是由于对象只接受字符串作为键名,所以element被自动转为字符串[object HTMLDivElement]。
为了解决这个问题,ES6 提供了 Map 数据结构。它类似于对象,也是键值对的集合,但是“键”的范围不限于字符串,各种类型的值(包括对象)都可以当作键。也就是说,Object 结构提供了“字符串—值”的对应,Map 结构提供了“值—值”的对应,是一种更完善的 Hash 结构实现。如果你需要“键值对”的数据结构,Map 比 Object 更合适。
上面代码在新建 Map 实例时,就指定了两个键name和title
size属性返回 Map 结构的成员总数。
const map = new Map();
map.set('foo', true);
map.set('bar', false);
map.size // 2
set方法设置键名key对应的键值为value,然后返回整个 Map 结构。如果key已经有值,则键值会被更新,否则就新生成该键。
const m = new Map();
m.set('edition', 6) // 键是字符串
m.set(262, 'standard') // 键是数值
m.set(undefined, 'nah') // 键是 undefined
set方法返回的是当前的Map对象,因此可以采用链式写法。
let map = new Map()
.set(1, 'a')
.set(2, 'b')
.set(3, 'c');
get方法读取key对应的键值,如果找不到key,返回undefined。
const m = new Map();
const hello = function() {console.log('hello');};
m.set(hello, 'Hello ES6!') // 键是函数
m.get(hello) // Hello ES6!
has方法返回一个布尔值,表示某个键是否在当前 Map 对象之中。
const m = new Map();
m.set('edition', 6);
m.set(262, 'standard');
m.set(undefined, 'nah');
m.has('edition') // true
m.has('years') // false
m.has(262) // true
m.has(undefined) // true
delete方法删除某个键,返回true。如果删除失败,返回false。
const m = new Map();
m.set(undefined, 'nah');
m.has(undefined) // true
m.delete(undefined)
m.has(undefined) // false
clear方法清除所有成员,没有返回值。
let map = new Map();
map.set('foo', true);
map.set('bar', false);
map.size // 2
map.clear()
map.size // 0
9.itertor遍历器
9.1.基本概念
let target = [1, 2, 34, 6, 8, 45, 31, 2]
function myinter(arr) {
let index = 0
return {
next() {
return index < arr.length ? { value: arr[index++], done: false } : { value: undefined, done: true }
//设置index,使得每次调用next方法时,index加一,对应数组的索引值
}
}
}
let it = myinter(target)//函数调用
// console.log(it.next())
// console.log(it.next())
// console.log(it.next())
// console.log(it.next())
for (let i = 0; i <= target.length; i++) {
console.log(it.next())//调用封装后的next方法
}
9.2.接口部署
对象无法使用for of遍历,因为内部没有遍历器
所有能够用for of遍历的对象,需要在它的Sysbol.itertor属性上部署一个itretor接口
- 部署好接口后,对象便可以使用for of遍历
10.Generator函数
10.1.两个特征
异步解决的方案,是一个状态机,封装了多个状态
- 1.function后有个*
- 2.函数体内使用yield定义不同的内部状态
10.2.初步使用
function* fn() {
yield "hello";//第一个状态
yield "world";//第二个状态
return "endconing";//第三个状态
}
//调用函数
let fn1 = fn()//函数不会立即执行,返回一个遍历器对象
//第一次调用,Generator函数开始执行,直到遇到第一个 yield 语句为止。 next
//方法返回一个对象,
//它 的 value 属性就是当前 yield 语句的值hello, done 属性的值false,表示
//遍历还没有结束
let a1= fn1.next()
console.log(a1
// 第二次调用,Generator函数从上次 yield 语句停下的地方,一直执行到下一个
//yield 语句。 next 方法
// 返回的对象的 value 属性就是当前 yield 语句的值world, done 属性的值
//false,表示遍历还没有结束。
let a2= fn1.next()
console.log( a2)
// 第三次调用,Generator函数从上次 yield 语句停下的地方,一直执行到 return 语句
// (如果没有return语句,就执行到函数结束)。next 方法返回的对象的value属性,
// 就是紧跟在 return语句后面的表达式的值(如果没有 return 语句,则 value 属
//性的值为undefined),
// done 属性的值true,表示遍历已经结束
let a3=fn1.next()
console.log( a3)
// 第四次调用,此时Generator函数已经运行完毕, next 方法返回对象的 value 属
//性为 undefined,
// done 属性为true。以后再调用 next 方法,返回的都是这个值。
let a4=fn1.next()
console.log( a4)
10.3.与itertor接口的关系
相似之处在于,都能返回紧跟在语句后面的那个表达式的值。区别在于每次遇到yield,函数暂停执行,下一次再从该位置继续向后执行,而return语句不具备位置记忆的功能。一个函数里面,只能执行一次(或者说一个)return语句,但是可以执行多次(或者说多个)yield表达式。
11.数组解构赋值惰性求值
12.class类
12.1.class基本语法
12.2.静态成员
12.3.类继承
12.3.1.基本语法
Class 可以通过关键字实现继承,这比 ES5 的通过修改原型链实现继承,要清晰和方便很多。
上面代码定义了一个类,该类通过关键字,继承了类的所有属性和方法。但是由于没有部署任何代码,所以这两个类完全一样,等于复制了一个类。下面,我们在内部加上代码。
上面代码中,方法和方法之中,都出现了关键字,它在这里表示父类的构造函数,用来新建父类的对象。
子类必须在方法中调用方法,否则新建实例时会报错。这是因为子类自己的对象,必须先通过
父类的构造函数完成塑造,得到与父类同样的实例属性和方法,然后再对其进行加工,加上子
类自己的实例属性和方法。如果不调用方法,子类就得不到对象。
12.3.2super 关键字
super 关键字需要写下子类this之前,相当于借用了父类的构造函数
图下:子类需要继承父类的tostring方法,需要使用super.tostring的方式
13.新定义的的Object方法
1.Object.setPrototypeOf
2.Object.keys
3.Object.values
4.Object.entries
5.getOwnPropertyDescriptor
6.Object.assign()
Object.assign()方法用于对象的合并,将源对象(source)的所有可枚举属性,复制到目标对象(target)。
const target = { a: 1 };
const source1 = { b: 2 };
const source2 = { c: 3 };
Object.assign(target, source1, source2);
target // {a:1, b:2, c:3}
注意,如果目标对象与源对象有同名属性,或多个源对象有同名属性,则后面的属性会覆盖前面的属性。
const target = { a: 1, b: 1 };
const source1 = { b: 2, c: 2 };
const source2 = { c: 3 };
Object.assign(target, source1, source2);
target // {a:1, b:2, c:3}
- 如果只有一个参数,Object.assign()会直接返回该参数。
const obj = {a: 1};
Object.assign(obj) === obj // true
14.函数的rest参数与扩展运算符
14.1.rest参数
14.2.扩展运算符
15.数组中增加的一些方法
15.1.find,findindex,filter的比较
15.2.value,key,entries的比较
16.函数参数的解构赋值
17.箭头函数
上面代码之中,只有一个,就是函数的,所以都输出同样的结果。因为所有的内层函数都是箭头函数,都没有自己的,它们的其实都是最外层函数的。
18.链判断运算符
19.async 函数
//1.使用then方法调用
//2.使用await
//只能在async函数中使用,await之后只能是一个promise对象
19.2具体使用
//request.js封装请求
let baseUrl="http://192.168.24.36:3000/"
function http(url){
return $.ajax({
url:baseUrl+url,
type:"get"
})
}
//index.html页面中发送请求
let url="top/playList?cat=华语"
async function getdata(){
let cat=await http(url)
let id=cat.playlists[0].id
let detail=await http(`playlist/detail?id=${id}`)
let songId=detail.playlist.tracks[0].id
let songurl=await http(`song/url?id=${songId}`)
console.log(songurl)
}
getdata()
20总结
21.参考文献
- ECMAScript6 (原著:阮一峰)
- 深入理解ES6
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!