You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
classFoo{constructor(x,y){this._x=xthis._y=y}log(){console.log(`arguments: ${this._x}--${this._y}`)}getname(){return`${this._x}--${this._y}`}}constisPrivate=key=>{if(key[0]==='_'){thrownewError('Attempt to access private property.')}}consthandler={get(target,key){isPrivate(key)returnReflect.get(target,key)},set(target,key,value){isPrivate(key)returnReflect.set(target,key,value)}}constfoo=newFoo(1,2)foo._x//Error...
这个版本的proxy已经能完成最基础的工作,禁止访问私有变量。接下来继续处理可能会出现的两个问题。
重写toJSON方法
由于调用JSON.stringify时仍然会调用私有变量导致报错,因此这里需要做个处理。
//...consthandler={get(target,key){isPrivate(key)/* Here */if(key==='toJSON'){constobj={}for(constkintarget){if(k[0]!=='_'){obj[k]=target[k]}}return()=>obj}returnReflect.get(target,key)},set(target,key,value){isPrivate(key)returnReflect.set(target,key,value)}}
consthandler={get(target,key){isPrivate(key)/* Here */if(key==='toJSON'){constobj={}for(constkintarget){if(k[0]!=='_'){obj[k]=target[k]}}return()=>obj}returnReflect.get(target,key)},set(target,key,value){isPrivate(key)returnReflect.set(target,key,value)},getOwnPropertyDescriptor(target,key){constdesc=Reflect.getOwnPropertyDescriptor(target,key)if(key[0]==='_'){desc.enumerable=false}returndesc}}
The text was updated successfully, but these errors were encountered:
实现私有变量的几种方法
背景
这篇文章是多日前的笔记,放上issue方便整理查看。。
命名约定
以下划线为属性名称的前缀,并没有什么卵用
Symbol
私有变量名使用Symbol类型,假如外部无法访问Symbol值,那么也可以无法读取私有变量。但是可以使用
getOwnProperySymbols
或Reflect.keys()
遍历WeakMap
将私有变量储存于WeakMap中。虽然仍然可以通过get接口读取存储在WeakMap中的实例的私有变量,但可以避免直接遍历实例读取出其中的私有属性。
用普通对象也可以实现,而使用WeakMap的原因在于: 可以防止内存泄露,假如实例其他引用被删除后,WeakMap对应键名会自动消失。(详细可以看本目录的WeakMap笔记)
闭包
通过闭包将数据封装在调用时创建的函数作用域,从而使外部无法访问
未封装前的类
未封装前的类,外部可以访问并修改传入的变量,非常不安全
In
Out
初次尝试封装
实现封装后,变量仅能从内部,即类中访问。
In
Out
修复instanceof操作符
使用第一次封装用的技术后,由于构造函数(外层Foo)返回的是一个新的对象(内层Foo的实例),因此instanceof操作符的结果可能会有误。
为了让结果更容易理解,我修改了内层类名。
问题
原因
instanceof操作符返回的检测的是:实例的原型链上是否存在构造函数的原型,即
因此解决问题的方案很简单,将实例的原型设置为构造函数即可(注意,instanceof 只检测是否存在于原型链上)
In
Out
从丢失getter的现象来审视当前的原型链
背景
使用上一步的方法封装私有变量,但是会发现其中的getter丢失了。
首先来审视上一步封装方法背后的原型链是怎么样的:
内部Foobar实例 -> 外部Foo -> Object
原因在于,类中的getter-setter是挂载在原型上的,即
Foobar.prototype
。因此重写Foobar实例的原型后,会丢失getter。
解决问题的答案也就很明显了,将Foobar原型就近挂载到原型链上。
In
此时的原型链为:
Foobar(instance) -> Foobar.prototype -> Foo.prototype -> Object
Out
Proxy
拦截get-set
最基础的用法是通过读取key,命中命名约定的私有变量则拦截
这个版本的proxy已经能完成最基础的工作,禁止访问私有变量。接下来继续处理可能会出现的两个问题。
重写toJSON方法
由于调用
JSON.stringify
时仍然会调用私有变量导致报错,因此这里需要做个处理。避免遍历时读取私有变量
由于在使用for-in遍历目标时会读取私有变量导致报错,因此这里也需要做个处理--在遍历私有变量时,将私有变量的描述符设置为不可枚举
The text was updated successfully, but these errors were encountered: