如何定义一个安全的私有对象?

引言:

定义私有对象,或者私有属性对于开发工具库是比较重要的知识,在各种使用场景你不知道会出现什么情况它可能会篡改你不想让用户操作的对象和属性,因此安全的定义私有对象能保证代码库的稳定性。

定义一个简单的私有对象

通常情况下我们会通过匿名函数自执行的方式(闭包)获得一个私有对象,这样用户就不能随意篡改重要元数据了。

同时实现了一个 get 方法示意其提供 api 的方式。

js 复制代码
const o = (function(){
    const obj = {
       foo:'foo',
       bar:'bar',
    }
    return {
        get(key){
            return obj[key]
        }
    }
})();

export default o;

我们看到 obj 已经被很好的保护起来了。

意想不到的篡改

但是真的无法篡改了吗?未必!

正常情况下我们无论如何也无法篡改 obj 了,因为我们只能通过 get 方法获得 obj 的属性,而无法获取 obj 本身,要是可以 通过 obj 的属性获取到 obj 本身 就好了,但是 obj 上只存在 foobar 两个属性,显然无从下手,如果硬要做点什么,那么可以通过什么来做到呢?

有了! 原型原型链,我们可以通过修改原型来扩展方法和属性,obj 是一个对象,通过原型链我们可以知道他的原型是 Object.prototype 这么一来就好办了,要是给 Object.prototype 扩展一个获取自己的属性不就好了嘛~,Object.defineProperty要上场了,属性Vue2的小伙伴应该知道要怎么做了吧,接下来我们实现一下。

扩展一个 self 属性吧,作用就是返回自己。

js 复制代码
Object.defineProperty(Object.prototype,'self',{
    get(){
        return this
    }
})

接下来我们尝试篡改 obj

可以看到成功了。

预防

比较弱的预防是获取属性的时候判断是是不是自身拥有的属性

只返回自身属性

js 复制代码
const o = (function(){
    const obj = {
       foo:'foo',
       bar:'bar',
    }
    return {
        get(key){
            if(obj.hasOwnProperty(key)){
                return obj[key]
            }
        }
    }
})();

export default o;

更好的方式容易想到我们只需要打断原型链或者在创建的时候不继承原型就行了

打断原型链

js 复制代码
const o = (function(){
    const obj = {
       foo:'foo',
       bar:'bar',
    }
    // 打断原型链
    obj.__proto__ = undefined
    return {
        get(key){
            return obj[key]
        }
    }
})();

export default o;

不继承原型

Object.create(null) 创建的对象可以去除一些不干净的东西。

js 复制代码
const o = (function(){
    const obj = Object.create(null)
    Object.assign(obj,{
       foo:'foo',
       bar:'bar',
    })
    return {
        get(key){
            return obj[key]
        }
    }
})();
export default o;

私有属性

这个我们搞快点:

1、命名规范下划线

这个太弱了

js 复制代码
class Foo {
   __foo='foo'
}

不推荐

2、Symbol + 闭包

js 复制代码
const foo = Symbol('foo')
class Foo {
   [foo]='foo'
}
export default Foo

也比较弱,不是很推荐。

3、标准语法'#'

js 复制代码
class Foo {
   #foo='foo'
}
export default Foo

这个很完美了但是有浏览器兼容问题但未来不是问题,推荐。

4、自定义映射

js 复制代码
const foo = new WeakMap()
class Foo {
   constructor(){
       foo.set(this, "foo");
   }
}
export default Foo

如果再多一个私有属性呢,那就定义两个 WeakMap

js 复制代码
const foo = new WeakMap()
const bar = new WeakMap()
class Foo {
   constructor(){
       foo.set(this, "foo");
       bar.set(this, "bar")
   }
}
export default Foo

等价于

js 复制代码
class Foo {
   #foo='foo'
   #bar='bar'
}
export default Foo

如果是实例属性不是类属性可以

js 复制代码
const map = new WeakMap()
map.set('attributeName', 'value')

这种没有兼容性问题,当然后续兼容性会更好或者你有babel的话也可以直接使用最新的语法

csharp 复制代码
#attributeName
this.#attributeName

(完)

相关推荐
我又来搬代码了2 分钟前
【Android】【Compose】Compose知识点复习(一)
android·前端·kotlin·android studio
哆啦A梦15885 分钟前
【vue实战】商城后台管理系统 01 项目介绍
前端·javascript·vue.js
9号达人18 分钟前
Jackson序列化让验签失败?破解JSON转义陷阱
java·后端·面试
布茹 ei ai27 分钟前
5、基于 GEE 的 Sentinel-1 SAR 地震滑坡变化检测系统:2022 泸定地震案例
javascript·sentinel·遥感·gee·云平台
爱吃土豆的马铃薯ㅤㅤㅤㅤㅤㅤㅤㅤㅤ36 分钟前
java实现登录:多点登录互踢,30分钟无操作超时
java·前端
一字白首40 分钟前
Vue Router 进阶,声明式 / 编程式导航 + 重定向 + 404 + 路由模式
前端·javascript·vue.js
d111111111d42 分钟前
C语言中static修斯局部变量,全局变量和函数时分别由什么特性
c语言·javascript·笔记·stm32·单片机·嵌入式硬件·学习
广州华水科技1 小时前
单北斗变形监测在水库安全中的应用与维护该如何实施?
前端