前言
余为前端菜鸟,感姿势水平匮乏,难观前端之大局。遂决定循前端知识之脉络,以兴趣为引,辅以几分坚持,望于己能解惑致知、于同道能助力一二,岂不美哉。
本系列代码及文档均在 此处
依然很忙,继续啃老本。。。
lesson1 Symbol
概述
javaScript第七种原始数据类型Symbol
let s = Symbol('foo')
通过Symbol函数生成,每个Symbol类型的变量值都独一无二,作为一种类似于字符串的数据结构,可以避免变量名冲突
Symbol函数接收一个参数用于描述该Symbol实例,不影响生成的Symbol实例的值
Symbol值不能与其他类型进行运算(模板字符串中也不可以),可以显示转为字符串和布尔值(String(), Boolean())
Symbol作为属性名
不能用.,因为.是去取字符串对应属性名
在对象中使用作为属性名时,需使用否则也会被当做字符串
Symbol.for, Symbol.keyFor
let 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种。
举个 |
|