前端日拱一卒D10——ES6笔记之新特性篇
栏目: JavaScript · 发布时间: 7年前
内容简介:余为前端菜鸟,感姿势水平匮乏,难观前端之大局。遂决定循前端知识之脉络,以兴趣为引,辅以几分坚持,望于己能解惑致知、于同道能助力一二,岂不美哉。本系列代码及文档均在依然很忙,继续啃老本。。。
余为前端菜鸟,感姿势水平匮乏,难观前端之大局。遂决定循前端知识之脉络,以兴趣为引,辅以几分坚持,望于己能解惑致知、于同道能助力一二,岂不美哉。
本系列代码及文档均在 此处
依然很忙,继续啃老本。。。
lesson1 Symbol
概述
-
javaScript第七种原始数据类型Symbol
let s = Symbol('foo')通过Symbol函数生成,每个Symbol类型的变量值都独一无二,作为一种类似于字符串的数据结构,可以避免变量名冲突
Symbol函数接收一个参数用于描述该Symbol实例,不影响生成的Symbol实例的值
Symbol值不能与其他类型进行运算(模板字符串中也不可以),可以显示转为字符串和布尔值(String(), Boolean())
-
Symbol作为属性名
- 不能用
.,因为.是去取字符串对应属性名 - 在对象中使用作为属性名时,需使用
[s]否则也会被当做字符串
- 不能用
-
Symbol.for,Symbol.keyForlet s1 = Symbol.for("foo"); Symbol.keyFor(s1) // "foo" let s2 = Symbol("foo"); // 先搜索全局,已存在该key则返回已存在的 Symbol.keyFor(s2) // undefined 复制代码
内置Symbol值
-
Symbol.hasInstance对象的
Symbol.hasInstance属性指向一个内部方法,其他对象使用instanceOf判断实例时,会调用这个内部方法class Even { static [Symbol.hasInstance](obj) { return Number(obj) % 2 === 0; } } 1 instanceOf Even 复制代码 -
Symbol.isConcatSpreadable表示该对象用于Array.prototype.concat()时是否可以展开,数组默认可展开,默认值为undefined,对象默认不可展开
-
Symbol.species指向当前对象的构造函数,创造实例时会调用这个方法,即使用该属性返回的函数作为构造函数
static get [Symbol.species]() { return this; } 复制代码 -
Symbol.match,Symbol.replace,Symbol.split,Symbol.search -
Symbol.iterator指向该对象的默认遍历器方法
对象进行for...of循环时,会调用Symbol.iterator方法,返回该对象的默认遍历器
详见后续章节
-
Symbol.toPrimitive -
Symbol.toStringTag指向一个方法,在该对象上调用Object.prototype.toString()时,如果该属性存在,则他的返回值会出现在toString方法返回的字符串之中,比如[Object Array]新增内置对象举个例子:
JSON[Symbol.toStringTag]:'JSON'
lesson2 Set和Map
Set
基本
-
Set构造函数生成,成员值唯一,(判断与===区别在于NaN),两个空对象视为不同
-
实例属性和方法
- 属性:
Set.prototype.constructor,Set.prototype.size - 方法:
add(value),delete(value),has(value),clear()
Array.from可以将Set转为数组 // 数组去重 function dedupe(array) { return Array.from(new Set(array)); // return [...new Set(array)] } 复制代码 - 属性:
-
遍历
- keys(), values(), entries(), forEach() 方法
- 遍历顺序为插入顺序,或可用于设置指定顺序的回调函数
- Set的键名键值相同
- Set默认可遍历,默认遍历器生成函数是values方法,这意味着,可以省略values方法,直接用for...of循环遍历 Set
Set.prototype[Symbol.iterator] === Set.prototype.values -
...内部使用for ... of,故可以使用[...Set],转为数组后可以方便使用数组方法如map和filter
WeakSet
- 成员只能为对象
- 弱引用,垃圾回收机制对对象引用计数时不考虑WeakSet中对对象的引用
-
new WeakSet()可以接收任何具有Iterable接口的对象作为参数,但必须注意加入WeakSet的成员必须为对象 - WeakSet有以下三个方法:
add(value),delete(value),has(value),没有size属性,不可遍历(没有forEach和clear方法)
Map
基本
-
键值对的集合(Hash结构),键和对象不一样,不局限于字符串。
-
任何具有 Iterator 接口、且每个成员都是一个双元素的数组的数据结构都可以作为Map构造函数的参数
-
只有对同一个对象的引用或者严格相等的简单类型(包括NaN)才会生成一样的Map
-
实例属性和方法
- 属性:
Map.prototype.constructor,Map.prototype.size - 方法:
set(),get(),delete(value),has(value),clear()
- 属性:
-
遍历
- 类似上述Set的遍历
- Map 结构的默认遍历器接口(Symbol.iterator属性),就是entries方法
与其他数据结构转换
- 数组,对象,JSON互转
function strMapToObj(strMap) { let obj = Object.create(null); for (let [k,v] of strMap) { obj[k] = v; } return obj; } 复制代码
WeakMap
-
键名只能为对象
-
WeakMap的键名所指向的对象,不计入垃圾回收机制
-
WeakMap有以下三个方法:
get,set,delete(value),has(value),没有size属性,不可遍历(没有forEach和clear方法)
lesson3 Proxy
观察
- 举个栗子 当你为对象a赋值a.b=c时,你希望在b属性赋值时有一个范围大小的校验,超出范围抛错,这个时候我们可能会想到重载set方法,比如:
let a = {} Object.defineProperty(a, 'b', { set(x) { if (x>100) { throw new RangeError('invalid range') } this.b = x } }) 复制代码动手以后发现一个问题...这样会栈溢出,因为在set内再set了b的值,无限循环...变通一下:let a = {} Object.defineProperty(a, 'b', { get(x) { return this.c } set(x) { if (x>100) { throw new RangeError('invalid range') } this.c = x } }) 复制代码然而总要这么写感觉很麻烦,而且如果是对一类属性进行操作时,重复写很没必要,换用Proxy写法:let a = {} let handler = { set(obj, prop, value, receiver) { if (prop === 'b') { if (value>100) { throw new RangeError('invalid range') } } obj[prop] = value } } let proxy = new Proxy(a, handler) 复制代码看起来也舒服多了,而且可以根据属性名在set方法内做判断,更可扩展
庖丁解牛
-
代理proxy
let target = {}; let handler = {}; let proxy = new Proxy(target, handler); // 将代理的所有内部方法转发至目标 proxy.a = 1 => target.a = 1; target.b = 4 => proxy.b = 4; target !== proxy target.__proto__ === proxy.__proto__ // 应在代理对象上操作,代理才能生效 handler = {get(){return 12}} target.v // undefined proxy.v // 12 复制代码 -
Proxy支持的拦截操作
get(target, propKey, receiver) // proxy.foo, proxy['foo'] set(target, propKey, value, receiver) //proxy.foo = v, proxy['foo'] = v has(target, propKey) // propKey in proxy deleteProperty(target, propKey) // delete proxy[propKey] ownKeys(target) // Object.getOwnPropertyNames(proxy), Object.getOwnPropertySymbols(proxy), Object.keys(proxy) getOwnPropertyDescriptor(target, propKey) // Object.getOwnPropertyDescriptor(proxy, propKey) defineProperty(target, propKey, propDesc) // Object.defineProperty(proxy, propKey, propDesc), Object.defineProperties(proxy, propDescs) preventExtensions(target) // Object.preventExtensions(proxy) getPrototypeOf(target) // Object.getPrototypeOf(proxy) isExtensible(target) // Object.isExtensible(proxy) setPrototypeOf(target, proto) // Object.setPrototypeOf(proxy, proto) apply(target, object, args) // 拦截 Proxy 实例作为函数调用的操作,比如proxy(...args)、proxy.call(object, ...args)、proxy.apply(...) construct(target, args) // new proxy(...args) 复制代码
-
代理句柄handler 句柄对象的方法可以复写代理的内部方法,具体为上述的14种。
-
举个:chestnut:
function Tree() { return new Proxy({}, handler); } var handler = { get: function (target, key, receiver) { if (!(key in target)) { target[key] = Tree(); // 自动创建一个子树 } return Reflect.get(target, key, receiver); } } var tree = new Tree() tree.branch1.branch2.twig = "green" 复制代码 -
再来个:chestnut:
// 实现对in操作符隐藏属性 var handler = { has (target, key) { if (key[0] === '_') { return false; } return key in target; } }; var target = { _prop: 'foo', prop: 'foo' }; var proxy = new Proxy(target, handler); '_prop' in proxy // false 复制代码 -
特别注意
如果目标对象不可扩展或者目标对象的属性不可写或者不可配置时,代理不能生效,可能会报错
需注意一些特定的方法对返回值有要求,不如重写isExtensible方法时,返回值与目标对象的isExtensible属性应一致,否则会报错
利用代理重写可以做很多事情比如隐藏属性、对某些属性、操作符屏蔽、拦截内在方法并且加上自己想要的逻辑处理去得到预期结果等
-
饭后甜点
-
Proxy.revocable
返回一个对象,proxy属性对应Proxy实例,revoke属性为revoke方法可以取消Proxy实例
``js let {proxy, revoke} = Proxy.revocable(target, handler); proxy.foo = 1 revoke() proxy.foo // TypeError: Revoked ``` 复制代码 -
this问题
- 代理以后目标对象内部的this指向的是Proxy实例而不是目标对象
- 有时候可能因为this指向问题导致代理达不到预期效果
// jane的name属性实际存储在外部的WeakMap对象的_name上,导致后续取不到值 const _name = new WeakMap(); class Person { constructor(name) { _name.set(this, name); } get name() { return _name.get(this); } } const jane = new Person('Jane'); jane.name // 'Jane' const proxy = new Proxy(jane, {}); proxy.name // undefined 复制代码 - 某些原生对象的部分属性需要this指向原生对象时才能获取,如Date.getDate(),此时proxy get时需要注意this绑定原始对象
const target = new Date('2015-01-01'); const handler = { get(target, prop) { if (prop === 'getDate') { return target.getDate.bind(target); } return Reflect.get(target, prop); } }; const proxy = new Proxy(target, handler); proxy.getDate() // 1 复制代码
进阶
- TO BE CONTINUED!
lesson4 Reflect
初识
- Reflect对象与Proxy对象一样,是为了操作对象而提供的新API,存在的原因如下:
- 将Object对象的一些内部方法添加到Reflect对象上,且以后的新方法都部署到Reflect对象上,完成分离
- 让对象操作变成函数行为
- 修改Object对象一些内部方法在出错时的返回
- Proxy覆写对象方法时,提供一个Reflect对象用来获取原始方法,以设置默认值,再此基础上再做功能添加和修改
揭面
-
静态方法
对应于Proxy可覆写的方法,有13个静态方法
-
注意
- Proxy和Reflect联用的时候要小心,可能一个拦截会触发另一个拦截
let p = { a: 'a' }; let handler = { set(target, key, value, receiver) { console.log('set'); Reflect.set(target, key, value, receiver) }, defineProperty(target, key, attribute) { console.log('defineProperty'); Reflect.defineProperty(target, key, attribute); } }; let obj = new Proxy(p, handler); obj.a = 'A'; // set // defineProperty 复制代码在Reflect.set传入receiver的时候触发了Proxy.defineProperty,不传入receiver时不会触发defineProperty拦截 复制代码
- 对于参数的要求、转换和报错处理
:chestnut:
- 使用Proxy实现观察者模式
const person = observable({ name: '张三', age: 20 }); function print() { console.log(`${person.name}, ${person.age}`) } observe(print); person.name = '李四'; // 输出 // 李四, 20 /**************************/ const queuedObservers = new Set(); const observe = fn => queuedObservers.add(fn); const observable = obj => new Proxy(obj, {set}); function set(target, key, value, receiver) { const result = Reflect.set(target, key, value, receiver); queuedObservers.forEach(observer => observer()); return result; } 复制代码
lesson5 遍历器Iterator
遇见
-
why Iterator
js中数据集合的概念越来越多,如果能有一种统一的访问方式将是极好的。Iterator的设计就基于此,通过为相应数据结构部署iterator接口让该数据结构可通过统一的方式:for...of遍历
-
遍历过程:
- 创建一个指针对象指向当前数据结构的初始位置(遍历器对象实际为一个指针对象)
- 调用指针对象的next方法,直到指向数据结构的结束位置
// 遍历器生成函数 function makeIterator(array) { var nextIndex = 0; return { next: function() { return nextIndex < array.length ? {value: array[nextIndex++]} : {done: true}; } }; } 复制代码 -
一种数据结构,只要部署了Iterator接口,就视为可遍历的
相识
默认Iterator接口
- 默认的Iterator接口部署在[Symbol.iterator]属性上,
Symbol.iterator属性键为Symbol对象,值为一个函数,即遍历器生成函数,执行该函数会返回一个遍历器对象,该对象具有一个next方法,调用该方法可以返回{value, done}对象,代表了当前成员的信息 - 部分数据结构如Array、Set、Map、String等已经部署了Iterator接口,对象则需要手动添加这样的方法实现Iterator接口
- 对于非线性数据结构,Iterator接口实际上就是一种线性转换,下例为class实现遍历器
class RangeIterator { constructor(start, stop) { this.value = start; this.stop = stop; } [Symbol.iterator]() { return this; } next() { var value = this.value; if (value < this.stop) { this.value++; return {done: false, value: value}; } return {done: true, value: undefined}; } } function range(start, stop) { return new RangeIterator(start, stop); } for (var value of range(0, 3)) { console.log(value); // 0, 1, 2 } 复制代码
举个:chestnut:
-
实现指针
function Node(value) { this.value = value; this.next = null } // for...of时会调用改遍历器生成函数 Node.prototype[Symbol.iterator]= function() { // 返回的遍历器对象 var iterator = { next: next } // 当前成员 var current = this next() { if(current) { var value = current.value; // 移动指针 current = current.next; return { done: false, value: value }; } return { done: true, value: undefined }; } return iterator } // 新建对象,因为在原型上实现的遍历器生成函数,所以每个实例都实现了遍历器接口 var one = new Node(1); var two = new Node(2); var three = new Node(3); // 当前成员的next指向下一个成员,在next方法中实现指针移动 one.next = two; two.next = three; // 对对象使用for...of时,去查找[Symbol.iterator]属性,找到后循环调用next方法,直到返回值得done属性为true for (var i of one){ console.log(i); // 1, 2, 3 } 复制代码 -
如果
Symbol.iterator方法对应的不是遍历器生成函数,则会报错
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- 前端开发不得不知的ES6十大新特性
- 前端HTML5 一些你没用过的特性
- Gulp&Webpack搭建属于自己的特性化前端脚手架
- 『互联网架构』软件架构-redis特性和集群特性(中)(49)
- 『互联网架构』软件架构-redis特性和集群特性(上)(48)
- 『互联网架构』软件架构-redis特性和集群特性(下)(50)
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Essential PHP Security
Chris Shiflett / O'Reilly Media / 2005-10-13 / USD 29.95
Being highly flexible in building dynamic, database-driven web applications makes the PHP programming language one of the most popular web development tools in use today. It also works beautifully wit......一起来看看 《Essential PHP Security》 这本书的介绍吧!
随机密码生成器
多种字符组合密码
RGB HSV 转换
RGB HSV 互转工具