ES6

过滤器 Proxy

修改某些操作的默认行为,比方说 a 标签的跳转
又叫元编程

  • 作用:拦截操作,类似过滤器、代理器
1
2
//建立过滤器
var proxy = new Proxy(target, handler);

它有两个属性,分别是 target 目标, handler 处理方法

target

就是过滤器的目标

目标是什么类型的,那么过滤器就是什么类型的

handler

他是过滤器的处理方法,就是要告诉过滤器,你咋过滤的?
它本身是个对象

以下是 handler 中的几个方法

get:改变“读取”操作

你的所有获取属性的方法都叫 读取 方法

  • 比方说 arr[0],这是用 中括号 来读取 arr 中下标为零的元素
  • console.log() 点方法 获取 console 对象中的 log 方法
  • get 有 三个参数,分别是
    target 目标,比方说 obj.name,目标就是 obj
    key 就是你点之后的东西,比方说 obj.namekey 就是 name
    第三个不咋用

而过滤器中的 get 会改变你读取 target 的方法

  • 没有 get ,输出如下
1
2
3
4
5
6
7
8
9
10
11
12
var obj = {
name: "霍金",
};
//建立 关于目标 obj 的 Proxy 过滤器
var proxy = new Proxy(obj, {
//首先这里什么都没干
});

//通过代理来访问obj中的name属性
console.log(proxy.name);
//霍金
//什么都没干的时候过滤器就是 target 本身
  • 有 get 方法,输出如下
1
2
3
4
5
6
7
8
9
10
11
12
13
var obj = {
name: "霍金",
};
//建立 Proxy 过滤器
var proxy = new Proxy(obj, {
//当你在这里写了get的时候,就已经开始修改读取的方法了
//所有的读取都走get语句,现在语句里啥都没有,所以 proxy.name 是 undefined
get() {},
});

//通过代理来访问obj中的name属性
console.log(proxy.name);
//undefined
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
//建立过滤器
var proxy = new Proxy(
{ name: "name的val" },
{
//get 封掉了读方法
get(target, key) {
console.log("我拦截了读取操作");
if (key == "prototype") {
throw new Error("dont touch me");
}
return target[key];
},
}
);
//你的所有点方法啊,[]什么的都是get方法
console.log(proxy.name);
//我拦截了读取操作
//name的val

console.log(proxy.prototype);
//Uncaught Error: dont touch me
读对象,找不到抛出错误
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
function Person() {
this.name = "xiaopang";
}
var person1 = new Person();
var handler = {
get(target, key) {
if (key in target) {
return target[key];
} else {
throw new Error(`Cant find ${key} in ${target}`);
}
},
};
var proxy = new Proxy(person1, handler);
console.log(proxy.name);
//xiaopang

console.log(proxy.age);
//Uncaught Error: Cant find age in [object Object]
数组填负的下标,倒着找元素

问题描述:
有个数组 array = [0,1,2,3,4,5,6,7]
我 console.log(array[-1]),就输出 7

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
//rest参数,首先把传来的1,2,3,4,5,6,7压缩成数组,保存在rest中
function searchF(...rest) {
//写处理方法
let handle = {
//修改 get 读取方法
get(tar, key) {
//把要找的负数的下标变成数
//因为 key 是字符串,需要转换成数字
let index = Number(key);
if (key < 0) {
//如果下标小于零,那么就跟着我游戏规则完
key = tar.length + index;
}
//返回找到的元素,给 get 方法
return tar[key];
},
};
//这个 searchF 返回个过滤器
return new Proxy(rest, handle);
}
//这时候的 array 已经是过滤器了
var array = searchF(0, 1, 2, 3, 4, 5, 6, 7);

//读取,走get方法
console.log(array[-1]);
//7
创建 key 类型的标签

问题描述:
通过过滤器在页面中添加节点,key 为 啥类型的标签,并且可以为标签添加属性和内容

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
32
33
34
35
36
37
38
const creatDom = new Proxy(
{},
{
get(target, key) {
//这里的attrs承接创建标签的属性,other是标签的其他数据
return function (attrs = {}, ...other) {
//创建游离标签元素,key值是你想要创建啥标签
// 比方说 creatDom.a,key 就是 a
let ele = document.createElement(key);

//循环设置标签属性
for (let x of Object.keys(attrs)) {
ele.setAttribute(x, attrs[x]);
}

//这里用forin是不对的,forin 是取key的,这里的话就是下标了
for (let oth of other) {
if (typeof oth === "string") {
//创建文本节点
oth = document.createTextNode(oth);
}
ele.appendChild(oth);
}
return ele;
};
},
}
);

//a1承接过滤器返回的ele游离节点
var a1 = creatDom.a({ href: "123.html" }, "文本1", "我是个文本2");

//把节点插入到body中
document.body.appendChild(a1);

//others 中可以接着往下写下一级的东西,比方说如下
var a2 = creatDom.div({}, creatDom.ul({}, creatDom.li({}, "这是第一个")));
document.body.appendChild(a2);

在这里插入图片描述

不允许读取私有属性

要求描述:
不允许读写对象属性中以 _ 下划线打头的属性
比方说
const obj = {_pro:1}; 中的 _pro 就不被允许读写

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
32
33
34
35
36
37
const people = {
name: "Wangbaoqiang",
_nickname: "高冷男神",
};
function check(key, method) {
//如果它前面有下划线,代表咱要处理它,不让外面的人来读写!
if (key[0] == "_") {
throw new Error(`${method} is not use _`);
}
}
const handler = {
get(tar, key) {
check(key, "get");
return tar[key];
},
set(tar, key, val) {
check(key, "set");
tar[key] = val;
},
};
//设置过滤器
const proxy = new Proxy(people, handler);

console.log(proxy);
//Proxy {name: "Wangbaoqiang", _nickname: "高冷男神"}

//读取普通属性,No problem
console.log(proxy.name);
//Wangbaoqiang

//尝试读取私有属性_nickname
console.log(proxy._nickname);
//Uncaught Error: get is not use _

//尝试改写私有属性_nickname,死心吧~
proxy._nickname = "我就要改!!改不动md";
//Uncaught Error: set is not use _

set :改变“修改”操作

  • set 和 get 很相似,set 多了一个参数 value
  • 修改操作就是赋值呗~,看看下面的例子叭
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
const people = {
name: "xiaopang",
};

var proxy = new Proxy(people, {
//receiver 这参数蛮闲鱼的,有兴趣自己试试吧
set(target, key, value, receiver) {
if (key == "age") {
if (value < 18) {
console.log(`${key}太小了,送你一箱练习册`);
return;
}
}
//set就不用返回值了,你直接设置就可以了
target[key] = value;
},
});
//这里你开始了改写操作,所以走代理器中的set方法
proxy.age = 17;
//age太小了,送你一箱练习册

proxy.habit = ["sing", "sang"];
console.log(people);
////{name: "xiaopang", habit: Array(2)}

apply

我需要研究一下

ownKeys :封掉关键字的使用

我需要研究一下

Proxy.revocable();


遍历器接口

遍历原理

就是下标下移

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
function traversing(array) {
//游标
let index = 0;
return {
next: function () {
//三目运算符
return index < array.length
? { val: array[index++], able: true }
: { val: undefined, able: false };
},
};
}
var arr = traversing([1, 2, 3, 4]);
console.log(arr.next());
//{val: 1, able: true}

console.log(arr.next());
//{val: 2, able: true}

console.log(arr.next());
//{val: 3, able: true}

console.log(arr.next());
//{val: 4, able: true}

console.log(arr.next());
//{val: undefined, able: false}

function*

这玩意叫啥?
function* 这种声明方式(function 关键字后跟一个星号)会定义一个生成器函数 (generator function),它返回一个 Generator 对象。

  • 这里新出了个关键词 yield ,类似一个暂停符,到底有啥用请看下面的例子,
  • 这个星号放在哪里都行!
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
function* test() {
yield "我是第一句";
//yield相当于暂停符号,一步一步的执行,要用 next 手动执行这个玩意儿

yield "我是第二句";
return "yes";
}
var t = test();

console.log(t);
//test {<suspended>}

console.log(t.next());
//{value: "我是第一句", done: false}

console.log(t.next());
//{value: "我是第二句", done: false}

//跟指针一样一直下移
console.log(t.next());
//{value: "yes", done: true}

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

类 Class

  • ES6 中迎来了真正的Class

  • ECMAScript 2015 中引入的 JavaScript 类实质上是 JavaScript 现有的基于原型的继承的语法糖。类语法不会为 JavaScript 引入新的面向对象的继承模型。MDN 官方解释。

  • 定义类用如下的方法:

1
2
3
4
5
6
7
8
9
10
11
class Person {
constructor(name, age) {
this.name = name;
this.age = age;
}
show() {
console.log(`我叫${this.name},今年${this.age}岁`);
}
}
var p1 = new Person("张三", 18);
p1.show();
  • 类方法是加在原型上的。

Promise

  • 他是一个对象,代表异步操作最终完成或失败
  • 解决回调地狱的问题
  • 时序:then中的函数被放到了微任务队列,而不是立即执行,等事件队列被清空之后再继续执行。
  • 类方法:Promise.all()Promise.race(),里面承接的是Promise数组
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
32
33
let promise = new Promise((resolve, reject) => {
if (1) {
resolve("操作成功");
} else {
reject("操作异常");
}
});

function requestA() {
console.log("请求A成功");
return "A请求的结果";
}
function requestB(res) {
// 通过res来获得上一个返回来的结果
console.log("上一步的结果:" + res);
console.log("请求B成功");
return "B请求的结果";
}
function requestC(res) {
console.log("上一步的结果:" + res);
console.log("请求C成功");
}
function requestError() {
console.log("请求失败");
}

//then处理操作成功,catch处理操作异常
promise.then(requestA).then(requestB).then(requestC).catch(requestError);
// 请求A成功
// 上一步的结果:A请求的结果
// 请求B成功
// 上一步的结果:B请求的结果
// 请求C成功